2011-02-12 26 views
15

Il mio obiettivo è sviluppare una classe che possa generare un oggetto di una classe specificata.Come passare una classe parametrizzata come argomento

public class GetMe<T> { 
    public T get() { 
     Object obj = generateObject(); 
     return (T) obj; 
    } 
} 

Ora, so che questo non è possibile a causa della cancellazione. Quindi, possiamo passare in un'istanza di classe e usarlo per trasmettere.

public class GetMe<T> { 
    public GetMe<T>(Class<T> clazz) { 
     this.clazz = clazz; 
    } 

    public T get() { 
     Object obj = generateObject(); 
     return clazz.cast(obj); 
    } 
} 

Questo funziona benissimo! Finché la classe non è parametrizzata. Se lo è, allora ho un problema.

Non sono autorizzato a utilizzare List<String>.class. Se passo in un ParameterizedType (che di per sé è difficile da generare), non esiste un metodo cast da utilizzare.

Esiste un modo per uscire da questo pantano?

+0

C'è un modo per conservare i generici in fase di esecuzione, ma cos'è 'generateObject' e perché non può restituire un oggetto di tipo' T'? – ide

+0

guarda questo esempio, potrebbe aiutare: http://serdom.eu/ser/2007/03/25/java-generics-standardment-objects-of-type-parameter-without-using-class-literal –

+0

Diciamo ' generateObject() 'è un deserializzatore di terze parti. So che è di tipo T, perché l'ho serializzato in precedenza, ma il metodo restituisce comunque Object. Potrebbe anche essere il risultato di un metodo.invoke, che restituisce solo oggetto. –

risposta

2

Il problema con List<String> è che, a causa della cancellazione, sarebbe in fase di esecuzione indistinguibile da qualsiasi altro List<?>. Il modo più semplice per aggirare questo è di creare una nuova classe o interfaccia che ha la parte generica "fisso", come

public interface StringList extends List<String> { 
    /* nothing to see here */ 
} 

In questo modo si dispone di un tipo di token (l'oggetto StringList.class), che è possibile passare in giro in fase di esecuzione e specifica esattamente ciò che vuoi, ma senza bisogno di generici in fase di runtime.

+0

Mi piace questa idea, ma non avrei quindi bisogno di molte di queste classi "fisse"? C'è un modo per renderle in esecuzione -time? Ho usato l'elenco nel mio esempio, nel mio progetto è in realtà 'Mappa >', dove Dominio potrebbe essere uno di ~ 200 oggetto, alcuni dei quali sono essi stessi parametrizzati. –

1

Ecco solo una piccola idea. Non sono sicuro che si adatti al tuo contesto, tuttavia:

public class GetMe<T> 
{ 
    public List<T> getList() { 
     @SuppressWarnings("unchecked") 
     List<T> result = (List<T>) new LinkedList(); 
     return result; 
    } 
} 

Cheers!

+1

è dove mi sto appoggiando, solo così posso andare avanti con la mia vita (anche se è "meno corretto") –

5

Penso che super type tokens possa risolvere questo problema per voi.

+0

+1 perché i token di tipo super sono super-flessibili. Avrei dovuto menzionarli nella mia risposta. – Waldheinz

0

Il primo problema è come si pianifica di creare un'istanza di un oggetto List. Se divulgherai più di ciò che stai cercando di costruire, potremmo essere in grado di aiutarti meglio.

Si consiglia di utilizzare Tipo anziché Classe. Il tipo può rappresentare tutti i tipi generici, anche se non è piacevole lavorare con.

abstract public class GetMe<T> 
{ 
    Type type; 
    public GetMe<T>(Type type) 
    { 
     this.type = type; 
    } 
} 

Un altro problema è come creare un tipo generico come List<String>. Il "tipo di token super" sembra pulito nella sintassi, in realtà è praticamente

static class XX extends TypeReference<List<String>>{} 
.... 
Type typeListString = Util.extract(XX.class); 

io preferirei di gran lunga questo modo

List<String> f; 

Type typeListString = getDeclaredField("f").getGenericType(); 

In realtà, molti di questi quadri che fanno runtime fantasia magie generici stanno lavorando su solo campi di istanza.

0

Penso che la confusione derivi dal fatto che stai cercando di creare un oggetto da List<> che di fronte è un'interfaccia, non un oggetto.
Quindi, non importa quello che ci si provi, semplicemente non è possibile creare un'istanza di List<>, (le interfacce non sono classi effettivi, e non hanno costruttori)

provare a utilizzare un vincolo per evitare di avere messo le interfacce nella dichiarazione:

public class GetMe<T extends Object> 

Ciò garantisce che T è una classe reale e non un'interfaccia.

Problemi correlati