2011-12-09 7 views
9

¿Hay alguna forma de evitar el borrado de tipos y obtener acceso a un parámetro de tipo?Cómo evitar el borrado de 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(); 
     ... 
    } 
} 

necesito saber sobre T, y hacer cosas con ella. ¿Es posible, y si es así, cómo se puede hacer sin pasando la clase en el constructor o en cualquier lugar además del parámetro?

EDIT: El principal objetivo de esta pregunta es averiguar si hay ninguna forma práctica alrededor de tipo borrado.

Respuesta

5

AFACT, no hay ninguna forma práctica todo tipo de borrado porque no se puede pedir algo que el tiempo de ejecución no tiene acceso a. Asumiendo, por supuesto, usted acepta que la subclasificación de clases genéricas para cada enumeración que implemente la interfaz Bar es un trabajo práctico.

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í - Esta es otra alternativa basada en la reflexión si prefieres subclases para pasar el objeto 'Clase'. –

2

Si estás dispuesto/capaz de entregar una ficha de clase al constructor:

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

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

De esta manera, se puede producir objetos de tipo T con Class.newInstance(), el intento de echar a objetos arbitrarios T usando Class.cast(), etc.

¿Qué piensas hacer en baz()?

+0

Digamos que le pide a la clase dada una lista de valores y hace uso de esos valores. Pasar en la clase no es lo que quiero hacer. –

1

Como señala pholser en su respuesta, la única forma de lograr esto es pasando el objeto Class que representa el tipo T. Es debido a Type Erasure que algo como T.class no es posible porque T se borra antes del tiempo de ejecución.

Parece resistente a pasar en el objeto Class, pero es la única forma de utilizar el método getEnumConstants(). He aquí un ejemplo que figura auto:

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

¿De modo que no hay absolutamente ninguna forma de evitar el Type Erasure y descubrir que la clase pasó como 'T'?La idea de este hilo es averiguar si hay alguna forma de borrar el tipo. –

+1

@Chris: la reflexión es la única solución para escribir el borrado en Java. Pero no está más en desventaja de lo que tiene pasando el objeto 'Clase', aunque es molesto y parece redundante en el momento de la compilación. Observe que ya está confiando en la reflexión mediante el uso de 'Class # getEnumConstants()'. La única alternativa es un rediseño completo que elimine su dependencia de ese método. –

0

En algunos casos se puede utilizar una solución sugerida por Richard Gomes. Al crear instancias de clases anónimas, la información de clase de parámetro de tipo está disponible.

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 
} 
} 

Tenga en cuenta que varias instancias creadas de esta manera serán de diferentes clases anónimas, y si eso es un problema que puede ser que desee un A_String_Factory clase con una función createnew() basado en el clon para reemplazar las llamadas a nuevo.

Cuestiones relacionadas