c# java generics comparison

C#vs genéricos de Java



generics comparison (3)

He oído que la implementación de Java de Generics no es tan buena como la implementación de C #. En que la sintaxis se ve similar, ¿qué es inferior a la implementación de Java o es un punto de vista religioso?


La diferencia se reduce a una decisión de diseño de Microsoft y Sun.

El compilador implementa los genéricos en Java mediante borrado de tipos , lo que significa que la verificación de tipos se produce en tiempo de compilación y se elimina la información del tipo. Este enfoque se tomó para mantener el código heredado compatible con código nuevo usando genéricos:

De The Java Tutorials, Generics: Type Erasure :

Cuando se crea una instancia de un tipo genérico, el compilador traduce esos tipos mediante una técnica llamada borrado de tipo, un proceso donde el compilador elimina toda la información relacionada con los parámetros de tipo y los argumentos de tipo dentro de una clase o método. La borradura de tipo permite que las aplicaciones Java que usan genéricos mantengan la compatibilidad binaria con las bibliotecas y aplicaciones de Java creadas antes de los genéricos.

Sin embargo, con genéricos en C # (.NET) , el compilador no borra ningún tipo, y las comprobaciones de tipo se realizan durante el tiempo de ejecución. Esto tiene sus beneficios de que la información de tipo se conserva en el código compilado.

De la Wikipedia:

Esta opción de diseño se aprovecha para proporcionar funcionalidad adicional, como permitir la reflexión con preservación de tipos genéricos, así como para aliviar algunas de las limitaciones de borrado (como la imposibilidad de crear matrices genéricas). Esto también significa que no hay impacto en el rendimiento de los lanzamientos en tiempo de ejecución y las conversiones de box normalmente caras.

En lugar de decir "Los genéricos de .NET son mejores que los genéricos de Java", uno debe analizar la diferencia en el enfoque para implementar genéricos. En Java, parece que preservar la compatibilidad era una alta prioridad, mientras que en .NET (cuando se introdujo en la versión 2.0), la obtención de todos los beneficios de usar genéricos era una prioridad más alta.


También encontré this conversación con Anders Hejlsberg que también puede ser interesante. Para resumir los puntos que Anders Hejlsberg hizo con algunas notas adicionales: se crearon genéricos de Java para una compatibilidad máxima con la JVM existente que dio lugar a algunas cosas raras en comparación con la implementación que se ve en C #:

  • Escriba borrado obliga a la implementación a representar cada valor genérico parametrizado como Object . Mientras que el compilador proporciona conversiones automáticas entre Object y un tipo más específico, no elimina el impacto negativo del tipo moldes y el boxeo en el rendimiento (p. Ej., El Object se MyClass tipo específico MyClass o int tenía que estar encuadrado en Integer , lo que sería aún más grave para C # /. NET si siguieron el enfoque de borrado de tipo debido a los tipos de valores definidos por el usuario). Como dijo Anders: "no se obtiene ninguna de la eficiencia de ejecución" (que los genéricos reificados permiten en C #)

  • La borradura de tipo hace que la información esté disponible en tiempo de compilación no accesible durante el tiempo de ejecución . Algo que solía ser List<Integer> convierte en una List sin forma de recuperar el parámetro de tipo genérico en tiempo de ejecución. Esto dificulta la creación de escenarios de reflexión o generación dinámica de código en torno a los genéricos de Java. La respuesta SO más reciente muestra una forma de evitarlo a través de clases anónimas. Pero sin trucos, algo como generar código en tiempo de ejecución a través de la reflexión que obtiene elementos de una instancia de colección y lo pone en otra instancia de recopilación puede fallar en tiempo de ejecución durante la ejecución del código generado dinámicamente: la reflexión no ayuda a detectar discrepancias en List<Double> versus List<Integer> en estas situaciones.

Pero +1 para la respuesta que enlaza con la here de here Jonathan Pryor.


here hace un gran trabajo para romper las diferencias. El resumen rápido y sucio es ...

En términos de sintaxis y uso. La sintaxis es más o menos la misma entre los idiomas. Algunos caprichos aquí y allá (sobre todo en las limitaciones). Pero, básicamente, si puedes leer uno, probablemente puedas leer / usar el otro.

La mayor diferencia es en la implementación.

Java usa la noción de borrado de tipo para implementar genéricos. En resumen, las clases compiladas subyacentes no son en realidad genéricas. Compilan hasta Objeto y lanzamientos. En efecto, los genéricos de Java son un artefacto de tiempo de compilación y pueden subvertirse fácilmente en tiempo de ejecución.

Por otro lado, C #, en virtud del CLR, implementa los genéricos hasta el código de bytes. El CLR tomó varios cambios importantes para dar soporte a los genéricos en 2.0. Los beneficios son mejoras en el rendimiento, verificación y reflexión de seguridad de tipo profundo.

Una vez más, el here provisto tiene un desglose mucho más profundo. Los invito a leer