interfaz grafica ejemplos crear componentes como clase java jvm backwards-compatibility type-erasure

java - grafica - ¿Por qué no eliminar el borrado de tipo de la próxima JVM?



swing containers netbeans (4)

Java introdujo el borrado de tipo con genéricos en Java 5 para que funcionen en versiones anteriores de Java. Fue una compensación por compatibilidad. Desde entonces hemos perdido esa compatibilidad [1] [2] [3]: el bytecode se puede ejecutar en versiones posteriores de la JVM pero no en las anteriores. Esto parece la peor opción posible: hemos perdido información de tipo y aún no podemos ejecutar el código de bytes compilado para las versiones más nuevas de la JVM en versiones anteriores. ¿Que pasó?

Específicamente, estoy preguntando si hay razones técnicas por las que no se pueda eliminar el borrado de tipo en la próxima versión de la JVM (asumiendo que, como las versiones anteriores, su código de bytes no podrá ejecutarse en la última versión de todos modos).

[3]: El borrado de tipo se puede realizar de forma retrolambda una manera similar a la retrolambda para aquellos a quienes realmente les gusta.

Edit: Creo que la discusión de la definición de compatibilidad hacia atrás y hacia adelante está ocultando la pregunta.


Específicamente, estoy preguntando si hay razones técnicas por las que no se pueda eliminar el borrado de tipo en la próxima versión de la JVM (asumiendo que, como las versiones anteriores, su código de bytes no podrá ejecutarse en la última versión de todos modos).

Porque probablemente destruiría la compatibilidad hacia atrás. (Compatibilidad real hacia atrás ... no del tipo mítico del que habla su pregunta original).

Sí, esa es una razón técnica, porque la compatibilidad con versiones anteriores es una de las propiedades más importantes del lenguaje / plataforma Java. Al menos, esa es la perspectiva de los clientes que pagan de Oracle y Oracle.

Si el borrado de tipos deja de funcionar, de repente cientos de miles de millones de dólares de inversión en software basado en Java realizado por muchas, muchas empresas en los últimos 20 años están en riesgo.

Pregúntate a ti mismo esto. ¿Por qué Sun / Oracle no eliminó Thread.stop() ?


El borrado de tipo es más que una función de código de byte que puede activar o desactivar.

Afecta la forma en que funciona todo el entorno de ejecución. Si desea poder consultar el tipo genérico de cada instancia de una clase genérica, implica que se crea una metainformación, comparable a una representación de Class tiempo de ejecución, para cada creación de objeto de una clase genérica.

Si escribe una new ArrayList<String>(); new ArrayList<Number>(); new ArrayList<Object>() new ArrayList<String>(); new ArrayList<Number>(); new ArrayList<Object>() new ArrayList<String>(); new ArrayList<Number>(); new ArrayList<Object>() , no solo está creando tres objetos, también está creando potencialmente tres meta objetos adicionales que reflejan los tipos, ArrayList<String> , ArrayList<Number> y ArrayList<Object> , si no existían antes .

Tenga en cuenta que hay miles de firmas de List diferentes en uso en una aplicación típica, la mayoría de ellas nunca se utilizan en un lugar donde se requiere la disponibilidad de dicha Reflexión (debido a la ausencia de esta función, podríamos concluir que actualmente, todas ellas trabajo sin tal reflexión).

Esto, por supuesto, multiplica, mil tipos diferentes de listas genéricas implican mil tipos diferentes de iteradores genéricos, miles de separadores y encarnaciones de Stream, sin contar las clases internas de la implementación.

E incluso afecta a lugares sin una asignación de objetos que actualmente están explotando el borrado de tipo bajo el capó, por ejemplo, Collections.emptyList() , Function.identity() o Comparator.naturalOrder() , etc. devuelven la misma instancia cada vez que se invocan . Si insiste en que el tipo genérico capturado por partalar se pueda inspeccionar reflectivamente, esto no funcionará más. Así que si escribes

List<String> list=Collections.emptyList(); List<Number> list=Collections.emptyList();

tendría que recibir dos instancias distintas, cada una de las cuales informaría una diferencia en getClass() o el equivalente futuro.

Parece que las personas que desean esta habilidad tienen una visión estrecha de su método particular, donde sería genial si pudieran descubrir de manera reflexiva si un parámetro en particular es en realidad uno de dos o tres tipos, pero nunca piense en el peso de la carga. metainformación sobre cientos o miles de instancias genéricas de miles de clases genéricas.

Este es el lugar donde tenemos que preguntarnos qué es lo que obtenemos a cambio: la capacidad de admitir un estilo de codificación cuestionable (de esto se trata la alteración del comportamiento del código debido a la información que se encuentra a través de la Reflexión).

Hasta ahora, la respuesta solo abordaba el aspecto fácil de eliminar el borrado de tipo, el deseo de realizar una introspección del tipo de una instancia real. Una instancia real tiene un tipo concreto, que podría ser reportado. Como se mencionó en este comentario del , la demanda para eliminar el borrado de tipo a menudo también implica el deseo de poder convertir a (T) o crear una matriz a través de la new T[] o acceder al tipo de una variable de tipo a través de T.class .

Esto elevaría la verdadera pesadilla. Una variable de tipo es una bestia diferente del tipo real de una instancia concreta. Una variable de tipo podría resolver a, por ejemplo ? extends Comparator<? super Number> ? extends Comparator<? super Number> ? extends Comparator<? super Number> para nombrar un ejemplo (bastante simple). Proporcionar la metainformación necesaria implicaría que no solo la asignación de objetos se vuelve mucho más cara, sino que cada invocación de un solo método podría imponer estos costos adicionales, en una extensión aún mayor, ya que ahora no solo estamos hablando de la combinación de clases genéricas con clases reales, sino que también todas las combinaciones comodín posibles, incluso de tipos genéricos anidados.

Tenga en cuenta que el tipo real de un parámetro de tipo también podría referirse a otros parámetros de tipo, convirtiendo la verificación de tipo en un proceso muy complejo, que no solo tiene que repetir para cada conversión de tipo, si permite crear una matriz a partir de Eso, cada operación de almacenamiento tiene que repetirlo.

Además del gran problema de rendimiento, la complejidad plantea otro problema. Si observa la lista de seguimiento de errores de javac o preguntas relacionadas de , puede observar que el proceso no solo es complejo, sino también propenso a errores. Actualmente, cada versión menor de javac contiene cambios y correcciones con respecto a la coincidencia de firma de tipo genérico, lo que afecta a lo que se aceptará o rechazará. Estoy bastante seguro de que no desea que las operaciones JVM intrínsecas como conversiones de tipos, asignaciones de variables o almacenes de matrices sean víctimas de esta complejidad, teniendo una idea diferente de lo que es legal o no en cada versión o rechazando repentinamente lo que javac aceptó en tiempo de compilación debido a las reglas no coincidentes.


Su comprensión de la compatibilidad hacia atrás es incorrecta.

El objetivo deseado es que las nuevas JVM puedan ejecutar el código antiguo de la biblioteca correctamente y sin cambios, incluso con el nuevo código. Esto les permite a los usuarios actualizar sus versiones de Java de manera confiable incluso a versiones mucho más nuevas de las que se escribió el código.


Hasta cierto punto, el borrado se eliminará en el futuro con el proyecto valhalla para permitir implementaciones especializadas para tipos de valor.

O para decirlo con más precisión, el borrado de tipo realmente significa la ausencia de especialización de tipo para genéricos, y Valhalla introducirá la especialización sobre primitivos.

Específicamente, estoy preguntando si existen razones técnicas por las que no se pueda eliminar el borrado de tipo en la próxima versión de JVM.

Actuación. No tiene que generar código especializado para todas las combinaciones de tipos genéricos, las instancias o las clases generadas no tienen que llevar etiquetas de tipo, cachés en línea polimórficos y verificaciones de tipo en tiempo de ejecución ( instanceof verificaciones generadas por el compilador) son simples y aún tenemos más del tipo de seguridad a través de verificaciones en tiempo de compilación.

Por supuesto, también hay muchos inconvenientes, pero la compensación ya se ha hecho, y la pregunta qué motivaría a los desarrolladores de JVM a cambiar esa compensación.

Y también podría ser una cuestión de compatibilidad, podría haber código que realice conversiones no verificadas para abusar de colecciones genéricas al confiar en el borrado de tipo que se rompería si se aplicaran las restricciones de tipo.