2011-01-29 16 views
63

Ho ottenuto un elenco, programmato in questo modo: public class MyList<T>. C'è un modo per usare la variabile T per ottenere il nome di classe (quindi posso, da MyList, sapere se T è String, Socket, ecc.)?Generici Java: ottieni lezione?

EDIT: Nevermind, ha trovato la risposta here.

+0

Sapete già la risposta, ma si potrebbe voler consultare http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/TypeLiteral.html – maaartinus

risposta

89

Risposta breve: non è possibile.

Risposta lunga:

causa il modo in cui i farmaci generici è implementato in Java, il tipo generico T non è mantenuto in fase di esecuzione. Ancora, è possibile utilizzare un membro dati privato:

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

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

Si sta vedendo il risultato di Type Erasure. Da quella pagina ...

Quando un tipo generico viene creata un'istanza, il compilatore traduce quei tipi da una tecnica chiamata tipo cancellazione - un processo in cui il compilatore rimuove tutte informazioni relative ai parametri di tipo e tipo argomenti all'interno di una classe o metodo . La cancellazione di tipo abilita le applicazioni Java che usano i generici per mantenere la compatibilità binaria con le librerie e le applicazioni Java che sono state create prima dei generici.

Ad esempio, Box <String> è tradotto a forma di scatola, che è chiamato tipo grezzo - un tipo grezzo è un classe o interfaccia generica nome senza argomenti tipo. Ciò significa che non è possibile scoprire quale tipo di oggetto utilizza una classe generica al runtime .

sembra Questo anche come questo question che ha un pretty good answer as well.

3

Io non sono sicuro al 100% se questo funziona in tutti i casi (ha bisogno di almeno 1 Java.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(); 
     } 
    }  
} 

Questo stamperà:

mappa del campo è di tipo Map
mappa campo ha un tipo parametrico di una mappa dei campi
ha un tipo parametrico di B

+0

Una volta ho provato a fare la stessa cosa durante il refactoring di General DAO, quindi ho analizzato alcuni esempi di codice simili. Non ricordo perché, ma ho deciso di non seguire questo approccio (penso che non abbia funzionato bene in tutti i casi, forse la gerarchia delle classi era obbligatoria). Il tuo esempio funziona :) +1 P.S. Alcuni tutorial estesi che ho trovato: http://www.artima.com/weblogs/viewpost.jsp?thread=208860 –

+0

Ho trovato l'articolo originale da cui ho estratto questo (l'esempio sopra è estratto da uno dei nostri lavori- progetti): http://tutorials.jenkov.com/java-reflection/generics.html#fieldtypes L'articolo dice che funziona solo con i campi pubblici, ma non è vero, puoi accedere ai campi protetti e privati ​​anche tramite la riflessione (solo usa getDeclaredField invece di getField) – esaj

+1

Questo non risponde alla domanda. Questo ottiene il tipo usato nel dichiarare un campo. Come è rilevante? – newacct

39

mi piace la soluzione da

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

Questa soluzione funziona bene per me. Il vantaggio non è necessario per passare parametri aggiuntivi come le altre soluzioni citate. Problemi durante l'utilizzo di questo? –

+0

funziona ancora correttamente – wutzebaer

+11

Questo funziona solo se la classe di runtime è una sottoclasse diretta della superclasse generica. –