2010-09-01 11 views
6

(Questo è un po un follow-up alla mia previous question)Come ottenere il valore <?> per un oggetto Foo <?>?

Ho un oggetto Foo<?>, foo. Foo<T> è un'interfaccia.

Come ottenere il valore del tipo nascosto dietro lo <?>?

noti che questo non è banale, come foo può essere per esempio un oggetto della classe Bar<String>, dove Bar<T> implements Foo<T>, o qualche classe anonyomus attuazione interfaccia FloatFoo, dove FloatFoo extends Foo<Float>. Ho bisogno di una soluzione che funzioni in tutti i casi.

Grazie in anticipo :)

+0

Foo è la tua interfaccia? Sei in grado di implementare metodi aggiuntivi? – Arne

+0

Sì, ci ho pensato: un metodo 'getType()' avrebbe risolto il problema. Probabilmente finirò con una soluzione come questa. – mik01aj

risposta

2

La soluzione finale (e forse la migliore possibile): ho rifattorizzato il mio codice, quindi non ne ha bisogno. Ho spostato tutto il codice che necessitava del parametro type in Foo, quindi ho potuto fornire un'implementazione appropriata all'interno della classe. Si è rivelato molto meno codice.

9

questo non è possibile utilizzando la riflessione perché Java Generics ha il problema di Type Erasure. In fase di runtime i tipi che sono stati definiti per la classe generica Foo sono stati rimossi, quindi l'uso della reflection su quella classe non produrrà il suo tipo generico. Questo tipo di informazioni viene utilizzato solo nella compilazione per la sicurezza del tipo.

C# non presenta questo problema ed è possibile accedere al tipo di classe di una classe.

This è una panoramica delle differenze.

8

Bene, in breve, non è possibile.

Tuttavia, ciò che si può fare è ottenere il valore di <?> quando si utilizza FloatFoo.

In effetti, da quello che ricordo, i farmaci generici non sono tenuti in informazioni di classe.

tuttavia, quando si crea un sottotipo (sia esso di classe o di interfaccia) di un tipo generico, le informazioni generiche devono essere memorizzate in quanto possono definire alcuni dei metodi di firma del sottotipo.

Per fare un esempio, se il vostro Foo interfaceis dichiarato come:

public interface Foo<T> { 
    public T doIt(); 
} 

Avere un

public interface FloatFoo extends Foo<Float> 

implica questa interfaccia ha un metodo

public Float doIt(); 

dichiarato.

Per questo, il compilatore deve avere le informazioni sul tipo. E queste informazioni si rifletteranno nell'API di riflessione dal fatto che alla super classe FloatFoo saranno associati alcuni parametri Tipo. O almeno è quello che ricordo dai pochi casi che ho riscontrato in questi casi (o li ho elaborati, poiché a volte può essere obbligatorio)

Ma avrai informazioni molto più complete allo Angelika's generics FAQ.

+0

il problema è, che 'getMethod (" doIt "). GetReturnType()' restituisce 'Object', e se si eseguirà il metodo per vedere cosa viene restituito, a volte si otterrebbe un oggetto sottoclasse e talvolta' null'. – mik01aj

+3

correlati e forse utili: http://www.artima.com/weblogs/viewpost.jsp?thread=208860 – Arne

+0

@ m01 Il trucco dell'interfaccia che menziona Riduidel non sempre funziona. È stato menzionato come un esempio di alcuni dati presenti, ma il problema sottostante esiste ancora. Il collegamento menzionato da Arne fa riferimento a una soluzione alternativa creata da Neal Gaffer, uno degli sviluppatori di compilatori Java. – linuxuser27

1

ho finito con la creazione di un metodo getType() nell'interfaccia:

Class<T> getType(); 

forse non è la soluzione più elegante, ma sicuramente la più semplice.

+1

Ciò non funziona ancora se il tuo è, diciamo, Elenco . Il meglio che potresti restituire è List.class. Se la situazione diventa complessa, dai uno sguardo al pattern "Super Type Token": http://gafter.blogspot.com/2006/12/super-type-tokens.html –

Problemi correlati