2011-12-09 11 views
9

C'è un modo per evitare la cancellazione del tipo e ottenere l'accesso a un parametro di tipo?Evitare la cancellazione del tipo Java

public class Foo<T extends Enum<?> & Bar> { 
    public Foo() { 
     // access the template class here? 
     // i.e. : 
     baz(T.class); // obviously doesn't work 
    } 

    private void baz(Class<T> qux) { 
     // do stuff like 
     T[] constants = qux.getEnumConstants(); 
     ... 
    } 
} 

ho bisogno di sapere su T, e fare le cose con esso. E 'possibile, e in caso affermativo, come può essere fatto senza passando nella classe nel costruttore o ovunque oltre il parametro?

EDIT: Lo scopo principale di questa domanda è quello di scoprire se c'è alcun modo pratico intorno tipo cancellazione.

risposta

5

AFACT, non v'è alcun modo pratico intorno cancellazione di tipo perché non si può chiedere qualcosa, che il runtime non ha accesso a. Supponendo naturalmente che tu accetti che le classi generiche di sottoclasse per ogni enum che implementa l'interfaccia Bar sia un lavoro pratico.

enum Test implements Bar { 
    ONE, TWO 
} 

class Foo<T> extends FooAbstract<Test> { 
    public Foo() { 
     ParameterizedType genericSuperclass = 
       (ParameterizedType) getClass().getGenericSuperclass(); 
     baz((Class<T>) genericSuperclass.getActualTypeArguments()[0]); 
    } 

    private void baz(Class<T> qux) { 
     T[] constants = qux.getEnumConstants(); 
     System.out.println(Arrays.toString(constants)); // print [ONE, TWO] 
    } 
} 

interface Bar { 
} 

class FooAbstract<T extends Enum<?> & Bar> { 
} 
+2

+1 Sì - Questa è un'altra alternativa basata sulla riflessione se si preferisce la sottoclasse per passare l'oggetto 'Class'. –

2

Se siete disposti/in grado di consegnare un gettone di classe al costruttore:

public Foo(Class<T> clazz) { 
    baz(clazz); 
} 

private void baz(Class<T> qux) { 
    // ... 
} 

In questo modo, è possibile produrre oggetti di tipo T con Class.newInstance(), il tentativo di gettare oggetti arbitrari a T utilizzando Class.cast(), ecc.

Che cosa intendi fare in baz()?

+0

Diciamo che chiede alla classe data un elenco di valori e fa uso di quei valori. Passare in classe non è quello che voglio fare. –

1

Come sottolinea il pholser nella sua risposta, l'unico modo per ottenere ciò è passare l'oggetto Class che rappresenta il tipo T. È a causa di Type Erasure che qualcosa come T.class non è possibile perché T viene cancellato prima del runtime.

Sembri resistente al passaggio nell'oggetto Class, ma è l'unico modo per utilizzare il metodo getEnumConstants(). Qui è un self esempio contenuto:

public class Foo<T extends Enum<?> & Bar> { 

    final Class<T> clazz; 

    public Foo(Class<T> clazz) { 

     this.clazz = clazz; 
    } 

    public void baz() { 

     T[] constants = clazz.getEnumConstants(); 

     System.out.println(Arrays.toString(constants)); 
    } 

    public static void main(String[] args) { 

     new Foo<MyEnum>(MyEnum.class).baz(); //prints "[A, B, C, D]" 
    } 
} 

public interface Bar { } 

public enum MyEnum implements Bar { A, B, C, D; } 
+2

Quindi non c'è assolutamente alcun modo per aggirare la cancellazione del tipo e capire la classe passata come 'T'?L'idea di questo thread è scoprire se c'è un modo per aggirare la cancellazione del tipo. –

+1

@Chris - Reflection è l'unica soluzione alternativa per digitare la cancellazione in Java. Ma non vieni messo più in difficoltà da quello che hai passando nell'oggetto 'Class', anche se è fastidioso e sembra ridondante in fase di compilazione. Si noti che si sta già facendo affidamento sulla riflessione usando 'Class # getEnumConstants()'. L'unica alternativa è una completa riprogettazione che rimuove la tua dipendenza da quel metodo. –

0

In alcuni casi è possibile utilizzare una soluzione suggerita da Richard Gomes. Durante la creazione di istanze di classi anonime, sono disponibili le informazioni sulla classe del parametro type.

class A<T> 
{ 
    A() 
    { 
     java.lang.reflect.ParameterizedType parameterizedType = (java.lang.reflect.ParameterizedType) (this.getClass().getGenericSuperclass()); 
     System.out.println(parameterizedType.getActualTypeArguments()[0]); 
    } 
} 

public class Example { 
public static void main(String[] args) { 
    A<String> anonymous = new A<String>() {}; // prints java.lang.String 
} 
} 

Si noti che più istanze create in questo modo saranno di diverse classi anonime, e se questo è un problema che si potrebbe desiderare un A_String_Factory classe con una funzione CreateNew() sulla base di clone di sostituire le chiamate a nuovo.

Problemi correlati