2011-11-07 22 views
10

Suponiendo que T es un parámetro de tipo de clase, ¿por qué no puedo usar T.classNombre de clase de los parámetros de tipo en java?

Estaba escribiendo una función que descarga una página y la analiza según una clase aprobada. Para el análisis, utilizo otra función cuya firma es: ParseObject::parse(Class<T> classname)

<T> void downloadParse(){ 
    ParseObject obj; 
    obj.parse(T.class); //<--- why compiler error here?? (whereas something like Integer.class is allowed) 
} 
+2

respuesta corta: 'tipo de borrado'. Google puede hacer el resto :) – laher

Respuesta

15

genéricos de Java se implementan a través de type erasure. Solo se pueden usar para verificar el tiempo de compilación. Después de la compilación, el objeto cambia al objeto común más bajo. (En este caso Object.class).

El bytecode compilado no tiene idea de qué es T.

Si desea tener acceso a la clase, es necesario cambiar el método a:

<T> void downloadParse(Class<T> cls){ 
    ParserObject obj; 
    obj.parse(cls); 
} 
+0

¡DEMASIADO RÁPIDO! ¡¡Gracias!! le ganas a Google Man :) No entiendo la respuesta al 100%, googleará más. Por cierto, he hecho lo mismo que sugerí. Solo necesitaba pasar el parámetro 'cls' alrededor de algunas funciones y almacenarlo en una variable de clase en mi programa real. (se sintió raro al hacer eso) –

+1

Es un poco raro, pero esa es la única manera de hacerlo. Si Java alguna vez obtiene genéricos reificados, hará la vida mucho, mucho más fácil. –

+4

Sin embargo, no tiene mucho sentido usar esto. Simplemente use 'Clase ' para obtener el mismo efecto. Solo tiene sentido si necesita aplicar algún tipo, p. Ej. '> void dp (Clase cls)'. Una buena regla de golpe para los genéricos: trate de evitarlos el mayor tiempo posible;) – sfussenegger

2

Erasure es el malo aquí. A partir de los tutoriales de Java:

Por ejemplo, la caja se traduce al tipo de caja, que se llama el tipo cruda - un tipo de crudo es una clase o interfaz nombre genérico y sin ningún argumentos de tipo. Esto significa que no puede encontrar el tipo de objeto que está usando una clase genérica en tiempo de ejecución. Las siguientes operaciones no son posibles :

public class MyClass<E> { 
    public static void myMethod(Object item) { 
     if (item instanceof E) { //Compiler error 
      ... 
     } 
     E item2 = new E();  //Compiler error 
     E[] iArray = new E[10]; //Compiler error 
     E obj = (E)new Object(); //Unchecked cast warning 
    } 
} 

las operaciones que se muestran en negrita tienen sentido en tiempo de ejecución debido a que el compilador elimina toda la información sobre el argumento de tipo real (representado por el parámetro de tipo E) en tiempo de compilación.

Con Erasure, se elimina la información de tipo, y todo es simplemente un objeto:

Cuando se crea una instancia de un tipo genérico, el compilador traduce esos tipos por una técnica llamada Tipo de borrado - un proceso donde el compilador elimina toda la información relacionada con los parámetros de tipo y escribe argumentos dentro de una clase o método. La eliminación de tipos habilita las aplicaciones Java que usan genéricos para mantener la compatibilidad binaria con las bibliotecas y aplicaciones de Java que se crearon antes de los genéricos.

A continuación, el compilador vuelve a introducir la clase "T" como modelos en cualquier lugar que se requiera. T no "existe" dentro del genérico, por lo que no puede crear un objeto de clase T. En las llamadas dentro y fuera de lo genérico, el compilador emite los Objetos en la clase "T".

Google "java erasure" para obtener más información sobre cómo funciona esto. Wikipedia proporciona some examples.

2

Como han dicho otros, eso no es posible. Pero dado que es un método sin argumentos y sin retorno, ¿qué esperarías que fuera T?

Algo que se puede encontrar de vez en cuando es la siguiente:

<T> T foo(Class<T> cls) { 
    Object o = ...; 
    return cls.cast(o); 
} 

// usage - perfectly type safe 
String s = foo(String.class); 

Además, a veces es posible obtener argumentos de tipo genérico, por ejemplo aquí:

class Foo implements Iterable<String> { 
    // snip 
} 

ParameterizedType pt = (ParameterizedType) Foo.class.getGenericInterfaces()[0]; 
System.out.println(pt); // prints java.lang.Iterable<java.lang.String> 

Class<?> at = (Class<?>) pt.getActualTypeArguments()[0]; 
System.out.println(at.getName()); // prints java.lang.String 

Pero eso es otra historia;)

Cuestiones relacionadas