2011-09-08 11 views
5

Ciao, ho un metodo che dovrebbe restituire risultati diversi a seconda del tipo.Verifica l'istanza di generico?

Posso fare così per controllare il tipo generico.

public <T> T search(final String query){ 
T returnValue = null; 
if (returnValue instanceof String){ } 
if (returnValue instanceof Integer){ } 
if (returnValue instanceof MyObject){ } 

Ma perché non posso fare così?

public <T> T search(final String query){ 
T returnValue = null; 
if (T instanceof String){ } 
if (T instanceof Integer){ } 
if (T instanceof MyObject){ } 

Codice di chiamata.

String id = myObjcet.<String> search("select ..."); 

risposta

4

Java genera generici "per cancellazione". Ciò significa che in fase di esecuzione non c'è (quasi) alcuna conoscenza dei generici. Invece, il compilatore controlla i generici, ma sotto la copertura converte tutto in Object (o al limite di generics più vicino).

Se decompilare che metodo che utilizza javap, vedrai che si legge:

public Object search(... 

viene rimosso ogni riferimento al T.

Questa è una seria limitazione dei generici in Java, che si riflette spesso anche nelle classi JRE ai costrutti con:

SomeClass<String> x = new SomeClass<String>(String.class); 

Qualora sia necessaria la terza ripetizione di stringa (String.class) poiché il costruttore ha bisogno di sapere su quale classe sta operando.

Questo paradigma, nonostante sia orribile, potrebbe risolvere il tuo problema.

Le informazioni sui generici sono in realtà contenute nei file .class, come metadati, possono essere ispezionate utilizzando il reflection e in parte anche risolte. Tuttavia, questo non è possibile in un caso come il tuo, ma è ad esempio utilizzato dagli ORM sui getter delle liste. per esempio, usando Hibernate, un getter come questo:

public List<Group> getGroups() { 

può essere ispezionato da Hibernate in modo da sapere che l'elenco dovrebbe contenere le istanze di gruppo, adattando le sue query di conseguenza.

(Tuttavia, anche se i generici non sono implementati in questo modo, T non è un'istanza, è una classe, scrivere String instanceof String è ugualmente sbagliato. Dovrebbe essere se (T.equals (String.class)))

+0

Grazie mille per questa splendida spiegazione, accetterò la tua risposta non appena me lo consentirà. – Farmor

1

Perché T viene cancellato in fase di esecuzione. È solo lì in fase di compilazione. returnValue è la variabile - è presente in fase di esecuzione.

1
public <T> T search(Class<T> clazz, String query){ 
T returnValue = null; 
if (clazz==String.class){ } 
if (clazz==Integer.class){ } 
if (MyObject.clazz.isAssignableFrom(clazz){ } 


String id = myObjcet.search(String.class, "select ...");