java - reificar - ¿Qué son los Genericos Reificados? ¿Cómo resuelven los problemas de Type Erasure y por qué no se pueden agregar sin grandes cambios?
reificación estética (4)
He leído el blog de Neal Gafter sobre el tema y aún no estoy seguro de algunos puntos.
¿Por qué no es posible crear implementaciones de la API de colecciones que conservan la información de tipo dado el estado actual de Java, la JVM y la API de colecciones existente? ¿No podrían estos reemplazar las implementaciones existentes en una versión futura de Java de manera que se preserve la compatibilidad con versiones anteriores?
Como ejemplo:
List<T> list = REIList<T>(T.Class);
Donde REIList es algo como esto:
public REIList<T>() implements List {
private Object o;
private Class klass;
public REIList(Object o) {
this.o = o;
klass = o.getClass();
}
... the rest of the list implementation ...
Y los métodos usan Object o y Class klass para obtener la información del tipo.
¿Por qué preservar la información genérica de la clase requiere cambios de lenguaje en lugar de solo un cambio en la implementación de JVM?
¿Qué no estoy entendiendo?
Contrariamente a las creencias de la mayoría de los desarrolladores de Java, es posible mantener la información del tipo de tiempo de compilación y recuperar esta información en tiempo de ejecución, a pesar de que es muy restringida. En otras palabras: Java proporciona genéricos reificados de una manera muy restringida .
En cuanto a la borradura de tipo
Tenga en cuenta que, en tiempo de compilación, el compilador tiene información de tipo completo disponible, pero esta información se descarta intencionalmente en general cuando se genera el código binario, en un proceso conocido como borrado de tipo . Esto se hace de esta forma debido a problemas de compatibilidad: la intención de los diseñadores de idiomas era proporcionar compatibilidad total con el código fuente y compatibilidad total con el código binario entre las versiones de la plataforma. Si se implementó de manera diferente, tendría que volver a compilar sus aplicaciones heredadas cuando migre a versiones más nuevas de la plataforma. De la forma en que se hizo, todas las firmas de métodos se conservan (compatibilidad con el código fuente) y no es necesario volver a compilar nada (compatibilidad binaria).
En cuanto a los genéricos reificados en Java
Si necesita mantener la información del tipo de tiempo de compilación, necesita emplear clases anónimas. El punto es: en el caso muy especial de las clases anónimas, es posible recuperar la información completa del tipo de tiempo de compilación en tiempo de ejecución que, en otras palabras, significa: genéricos reificados.
He escrito un artículo sobre este tema:
http://rgomes-info.blogspot.co.uk/2013/12/using-typetokens-to-retrieve-generic.html
En el artículo, describo cómo reaccionaron nuestros usuarios a la técnica. En pocas palabras, este es un tema oscuro y la técnica (o el patrón, si lo prefiere) parece extraña a la mayoría de los desarrolladores de Java.
Código de muestra
El artículo que he mencionado anteriormente tiene enlaces al código fuente que ejercita la idea.
El punto es que los genéricos reificados tienen soporte en el compilador para preservar la información de tipo, mientras que los genéricos borrados no lo hacen. AFAIK, el objetivo de borrar el texto en primer lugar era permitir la compatibilidad con versiones anteriores (por ejemplo, las JVM con versiones más bajas aún podían entender las clases genéricas).
Puede agregar explícitamente la información de tipo en la implementación, como lo hizo anteriormente, pero eso requiere código adicional cada vez que se usa la lista, y es bastante complicado en mi opinión. Además, en este caso, aún no tiene la verificación del tipo de tiempo de ejecución para todos los métodos de lista, a menos que agregue los controles usted mismo, sin embargo, los genéricos reificados garantizarán los tipos de tiempo de ejecución.
IIRC (y basado en el enlace), los genéricos de Java son solo azúcar sintáctico para la técnica existente de usar una colección de Objetos y lanzarlos hacia adelante y hacia atrás. Es más seguro y sencillo utilizar los genéricos de Java, ya que el compilador puede hacer las comprobaciones para que usted verifique que mantiene la seguridad del tipo de tiempo de compilación . El tiempo de ejecución, sin embargo, es un problema completamente diferente.
Los genéricos .NET, en cambio, crean realmente nuevos tipos: una List<String>
en C # es un tipo diferente que una List<Int>
. En Java, bajo las cubiertas, son lo mismo: una List<Object>
. Esto significa que si tiene uno de cada uno, no puede verlos en tiempo de ejecución y ver cómo fueron declarados, solo lo que son ahora.
Los genéricos reificados cambiarían eso, dando a los desarrolladores de Java las mismas capacidades que existen ahora en .NET.
No soy un experto en el tema, pero según tengo entendido, la información del tipo se pierde en el momento de la compilación. A diferencia de C ++, Java no usa un sistema de plantilla, la seguridad de tipo se logra completamente a través del compilador. En tiempo de ejecución, una lista es en realidad una lista, siempre.
Así que mi opinión es que se requiere un cambio en la especificación del lenguaje debido al hecho de que la información del tipo no está disponible para la JVM porque no está allí .