2011-01-29 19 views
63

Mam listę zaprogramowaną w ten sposób: public class MyList<T>. Czy istnieje sposób użycia zmiennej T do pobrania nazwy klasy (dzięki czemu mogę, od MyList, wiedzieć, czy T jest String, Socket itp.)?Generics Java - zdobyć klasę?

EDYCJA: Nieważne, znaleziono odpowiedź here.

+0

Znasz już odpowiedź, ale ty może zajrzeć pod http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/TypeLiteral.html – maaartinus

Odpowiedz

89

Krótka odpowiedź: Nie możesz.

Długa odpowiedź:

ze względu na sposób generycznych jest zaimplementowany w Javie, generyczny typ T nie jest utrzymywana w czasie wykonywania. Mimo to, można użyć Prywatny członek danych:

public class Foo<T> 
{ 
    private Class<T> type; 

    public Foo(Class<T> type) { this.type = type; } 
} 
24

Widzisz wynik Type Erasure. Od tamtej stronie ...

Gdy typ rodzajowy jest tworzony, kompilator tłumaczy te typy przez technika zwana typu usunięcia - do proces, w którym kompilator usuwa wszystkie informacje dotyczące typu i rodzaju parametrów argumenty w klasie lub w metodzie . Typ erasure umożliwia aplikacjom Java , które używają generics do , zachowują kompatybilność binarną z bibliotekami Java i aplikacjami, które zostały utworzone przed generycznymi.

Na przykład Box <String> jest tłumaczone wpisać Box, który jest zwany surowy typ - typ surowy jest rodzajowy klasy lub interfejsu nazwa bez argumentów typu. Oznacza to, że nie można dowiedzieć się, jaki typ obiektu klasy ogólnej jest używany w środowisku wykonawczym .

wygląda to też jak ten question który ma pretty good answer as well.

3

nie jestem w 100% pewien, czy to działa we wszystkich przypadkach (potrzebuje co najmniej Java 1.5):

import java.lang.reflect.Field; 
import java.lang.reflect.ParameterizedType; 
import java.lang.reflect.Type; 
import java.util.HashMap; 
import java.util.Map; 

public class Main 
{ 
    public class A 
    { 
    } 

    public class B extends A 
    {  
    } 


    public Map<A, B> map = new HashMap<Main.A, Main.B>(); 

    public static void main(String[] args) 
    { 

     try 
     { 
      Field field = Main.class.getField("map");   
      System.out.println("Field " + field.getName() + " is of type " + field.getType().getSimpleName()); 

      Type genericType = field.getGenericType(); 

      if(genericType instanceof ParameterizedType) 
      { 
       ParameterizedType type = (ParameterizedType) genericType;    
       Type[] typeArguments = type.getActualTypeArguments(); 

       for(Type typeArgument : typeArguments) 
       { 
        Class<?> classType = ((Class<?>)typeArgument);     
        System.out.println("Field " + field.getName() + " has a parameterized type of " + classType.getSimpleName()); 
       } 
      } 
     } 
     catch(Exception e) 
     { 
      e.printStackTrace(); 
     } 
    }  
} 

Wyjście to będzie:

Pole mapa jest typu mapą
Pole mapa ma parametryzowane type
polowego mapie ma parametryczne typu B

+0

Kiedy próbowałem zrobić podobne podczas refaktoryzacji General DAO, przeszedłem przez podobne próbki kodu. Nie pamiętam dlaczego, ale postanowiłem nie stosować takiego podejścia (myślę, że we wszystkich przypadkach nie działało dobrze, być może hierarchia klas była obowiązkowa). Twój przykład działa :) +1 P.S. Niektóre rozszerzone samouczki, które znalazłem: http://www.artima.com/weblogs/viewpost.jsp?thread=208860 –

+0

Znalazłem oryginalny artykuł, w którym to podniosłem (powyższy przykład jest wyodrębniony z jednej z naszych prac- projekty): http://tutorials.jenkov.com/java-reflection/generics.html#fieldtypes Artykuł mówi, że działa tylko z polami publicznymi, ale to nie prawda, możesz uzyskać dostęp do chronionych i prywatnych pól również za pomocą refleksji (tylko użyj getDeclaredField zamiast getField) – esaj

+1

To nie odpowiada na pytanie. Otrzymuje to typ używany do deklarowania pola. Jak to jest istotne? – newacct

39

podoba mi się rozwiązanie z

http://www.nautsch.net/2008/10/28/class-von-type-parameter-java-generics/

public class Dada<T> { 

    private Class<T> typeOfT; 

    @SuppressWarnings("unchecked") 
    public Dada() { 
     this.typeOfT = (Class<T>) 
       ((ParameterizedType)getClass() 
       .getGenericSuperclass()) 
       .getActualTypeArguments()[0]; 
    } 
... 
+0

To rozwiązanie działa dobrze dla mnie. Zaleta nie wymaga przekazywania dodatkowych parametrów, takich jak inne wspomniane rozwiązania. Wszelkie problemy podczas korzystania z tego? –

+0

nadal działa dobrze – wutzebaer

+11

Działa to tylko wtedy, gdy klasa środowiska wykonawczego jest bezpośrednią podklasą ogólnej klasy nadrzędnej. –