2009-08-24 13 views
5

Mi piacerebbe fare una classe che sembra sostanzialmente in questo modo:Ottenere la classe di un Java generico e implementazione dell'interfaccia di farmaci generici

public class MyClass<T implements Serializable) { 

    void function() { 
     Class c = T.class; 
    } 
} 

Due errori:
- non posso chiamare T.class, anche se posso farlo con qualsiasi altro tipo di oggetto
- Non riesco a far rispettare che T implementa Serializable in questo modo

Come posso risolvere i miei due problemi generici?

Acclamazioni

Nik

+0

Potrebbe aggiungere un esempio di ciò che si desidera effettivamente ottenere? – Zed

risposta

7

Non è possibile ottenere il tipo.

I generici sono implementati utilizzando qualcosa chiamato type-erasure.

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 digitare gli argomenti all'interno di una classe o di 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.

L'essenza di questo è che l'informazione sul tipo viene utilizzata dal compilatore e scartata, quindi non disponibile in fase di esecuzione.

Per quanto riguarda il far rispettare T implements Serializable, basta il seguente:

public class MyClass<T extends Serializable>) 
{ 
    public void function(T obj) 
    { 
    ... 
    } 
} 

Questo è semplicemente riferendo al è un rapporto, in modo da una classe che implementa Serializable, è unSerializable e può passare a function.

+1

Grazie per l'ottima spiegazione, ora capisco perché non funziona, e ho risolto il mio problema pratico con la soluzione proposta da gjrwebber. Grazie mille! :-) – niklassaers

3

Qualcosa in questo senso dovrebbe farlo.

private Class<T> dataType; 
Type type = getClass().getGenericSuperclass(); 
if (type instanceof ParameterizedType) { 
    ParameterizedType paramType = (ParameterizedType) type; 
    dataType = (Class<T>) paramType.getActualTypeArguments()[0]; 
} else if (type instanceof Class) { 
    dataType = (Class<T>) type; 
} 
+0

Grazie per la soluzione, questo mi ha aiutato a risolvere il problema e le altre risposte mi hanno aiutato a capire il problema. :-) Siete i migliori! :-) – niklassaers

+5

Ho ottenuto un sun.reflect.generics.reflectiveObjects.TypeVariableImpl non può essere lanciato su java.lang.Class, cosa mi manca? –

1

Non è possibile eseguire T.class perché java non sa in realtà quale classe T è in fase di runtime.

Tutte le informazioni vengono perse durante la compilazione.

per ottenere l'oggetto di classe per T è possibile chiamare getClass() in un'istanza di T (se si ha accesso a uno) o richiedere all'utente di passare l'oggetto di classe come argomento per function, come:

void function(Class<T> c) 
+0

La sintassi per il limite degli argomenti generici è non

+0

Ah right. Ho rimosso quella parte della mia risposta. – sepp2k

+0

Grazie per il feedback rapido. (1) Il problema è che nella mia funzione generica voglio usare le funzioni che prendono T.class come parametro di input. Se non riesco a farlo in questo modo, una soluzione non altrettanto buona sarebbe quella di istanziare un oggetto di classe T, ma come ho capito non posso nemmeno dire "nuovo T()", ancora una volta a causa della cancellazione del tipo? (2) Doh, non ha visto l'errore di battitura. Ma, il mio compilatore Java afferma che si aspetta una virgola in cui scrivo le implementazioni, questo è ciò che intendevo. EDIT: Grazie tkopec, extends ha funzionato molto meglio, non sapevo di poter estendere un'interfaccia – niklassaers

5

fare questo:

public class MyClass<T implements Serializable) { 

    void function(Class<T> tc) { 
     ... 
    } 
} 

In sostanza, è necessario passare nella classe in fase di esecuzione per vederlo. Si potrebbe anche fare qualcosa di simile:

public class MyClass<T implements Serializable) { 
    Class<T> ct; 
    public MyClass(Class<T> ct){this.ct = ct;} 

    void function() { 
     ... //you know what the class is here 
    } 
} 

È un po 'fastidioso, ma non è poi così grande di un fastidio generale.

+1

Grazie mille, questa è una soluzione elegante :-) – niklassaers

+0

Questa è una soluzione molto semplice e buona – satya

Problemi correlati