2009-07-14 3 views
5

Mi piacerebbe ottenere il tipo generico di una collezione, utilizzando la riflessione, in fase di esecuzione.Specifica generico tipo di raccolta param in fase di esecuzione (Java Reflection)

Codice (JAVA):

Field collectionObject = object.getClass().getDeclaredField(
    collectionField.getName()); 
//here I compare to see if a collection 
if (Collection.class.isAssignableFrom(collectionObject.getType())) { 
    // here I have to use the generic type of the collection 
    // to see if it's from a specific type - in this case Persistable 
    if (Persistable.class.isAssignableFrom(GENERIC_TYPE_COLLECTION.class)) { 
    } 
} 

C'è un modo di ottenere il tipo generico della collezione in Java in fase di esecuzione? Nel mio caso ho bisogno della classe .class del tipo generico della raccolta.

Grazie in anticipo!

+0

Io stavo affrontando un problema simile e questo è quello che finalmente lo risolse per me: http://stackoverflow.com/a/183232/639119 – Zds

risposta

17

Type erasure significa che le informazioni sul tipo generico di un oggetto non sono presenti al momento dell'esecuzione.

(Il link è alla relativa sezione del Java Generics FAQ di Angelika Langer, che dovrebbe rispondere a praticamente ogni domanda si potrebbe chiedere generici Java :)

Tuttavia, non siete realmente interessati nel tipo di un oggetto - ti interessa il tipo di un campo . Ho letto male la domanda e, sebbene la risposta sia stata accettata, spero di rimediare risolvendolo ora :)

Se il campo non utilizza un parametro di tipo, è possibile farlo. Per esempio:

import java.lang.reflect.*; 
import java.util.*; 

public class Test 
{ 
    public List<String> names; 

    public static void main(String [] args) 
     throws Exception // Just for simplicity! 
    { 
     Field field = Test.class.getDeclaredField("names"); 

     ParameterizedType type = (ParameterizedType) field.getGenericType(); 

     // List 
     System.out.println(type.getRawType()); 

     // Just String in this case 
     for (Type typeArgument : type.getActualTypeArguments()) 
     { 
      System.out.println(" " + typeArgument); 
     } 
    } 
} 

Se il campo fosse in una classe T con il campo essendo List<T> allora dovreste conoscere l'argomento di tipo per l'istanza al fine di conoscere l'argomento tipo per la raccolta.

Traducendo questo nel tuo codice necessario è un po 'difficile anche se - si ha realmente bisogno di sapere l'argomento di tipo presso il punto di raccolta della classe. Per esempio, se qualcuno ha dichiarato:

public class StringCollection implements Collection<String> 

e poi ha avuto un campo di tipo StringCollection, che campo stesso non avrebbe alcuna argomenti di tipo. Farebbe quindi necessario controllare getGenericSuperType e getGenericInterfaces ricorsivamente fino hai trovato quello che volevi.

E 'davvero non sarà facile per farlo, anche se è possibile. Se fossi in te, proverei a cambiare il tuo design in modo da non averne bisogno.

+1

Il controllo ricorsivo in effetti non è facile, ci sono molti casi d'angolo da prendere in considerazione. E questo è solo il primo passo, quindi è necessario un equivalente IsAssignableFrom che gestisca anche i generici. Non consiglierei di provare a implementarlo da solo. Ho scritto una libreria che fa questo per te, chiamata gentyref. Vedi http://code.google.com/p/gentyref/. –

0

è possibile ottenere il tipo generico del campo di leggere l'oggetto con Field.getGenericType. Si noti che il campo può essere un tipo grezzo, essere un tipo raro (generico, ma con un argomento generico che è crudo), utilizzare il tipo dell'istanza, utilizzare i caratteri jolly, ecc

0

copiato dal mio post a: https://stackoverflow.com/questions/1004022/java-generic-class-determine-type/1005283#1005283

ho usato una soluzione simile a quello che spiega qui per un paio di progetti e l'ho trovato molto utile.

http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/

La jist di esso sta usando il seguente per determinare il tipo di parametro in fase di esecuzione:

public Class returnedClass { 
    ParameterizedType parameterizedType = 
    (ParameterizedType) getClass().getGenericSuperClass(); 
return (Class) parameterizedtype.getActualTypeArguments()[0]; 
} 
9

si può assolutamente fare quello che vuoi.Digitare cancellatura significa che non è possibile esaminare un'istanza di una raccolta per il suo tipo generico, ma è possibile ispezionare un campo per il suo tipo generico.

class Thing { 
    List<Persistable> foo; 
} 


Field f = Thing.class.getDeclaredField("foo"); 
if(Collection.class.isAssignableFrom(f.getType()) { 
    Type t = f.getGenericType(); 
    if(t instanceof ParameterizedType) { 
    Class genericType = (Class)((ParameterizedType)t).getActualTypeArguments()[0]; 
    if(Persistable.class.isAssignableFrom(genericType)) 
     return true; 
    } 
} 

C'è un sacco di cose che possono andare male qui, per esempio, se si dispone di

Class Thing<T> { 
    List<T> foo; 
} 

quindi quanto sopra non funziona.

+1

Sto indovinando questa riga: Classe genericType = (Class) ((ParameterizedType) t) .getActualTypeArguments [0]; deve essere Classe genericType = (Class) ((ParameterizedType) t) .getActualTypeArguments() [0]; ? – andersonbd1