2008-12-10 16 views
103

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?C# vs Java generics

+0

parece que esta pregunta ya se ha hecho - http://stackoverflow.com/questions/31693/differences-in-generics#31866 – serg10

+0

Comparación completa [aquí] (http://www.jprl.com/Blog/ archive/development/2007/Aug-31.html), con algunos enlaces. – Strelok

Respuesta

136

streloksi's link 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. Algunas peculiaridades aquí y allá (más notablemente en restricciones). Pero, básicamente, si puedes leer uno, probablemente puedas leer/usar el otro.

La mayor diferencia es en la implementación.

Java utiliza 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.

C# por otro lado, en virtud de la CLR, implementa 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.

De nuevo el proporcionado link tiene una mucho más en profundidad desglose os animo a leer

+1

Leí el enlace de Strelok, la [entrevista] de Anders Hejlsberg (http://www.artima.com/intv/generics2.html) y la [publicación de blog] de Eric Lippert (http://blogs.msdn.com /b/ericlippert/archive/2009/07/30/generics-are-not-templates.aspx). Pero todavía no puedo obtenerlo: ¿cómo C# no hace el borrado de tipo ** y ** los tipos de referencia comparten el mismo código IL? ¿Podrías expandir esto un poco? –

+0

@AlexanderMalakhov todos los tipos de referencia son un tamaño de palabra en el ensamblaje y se pueden manipular con las mismas instrucciones, por lo tanto, pueden compartir el mismo patrón de ensamblaje. ¿Dónde esperarías que difieran? – JaredPar

+0

Supongo que Java hace exactamente lo mismo. Entonces, ¿dónde está la información tipo? ¿Cómo, por ejemplo, la reflexión puede funcionar? –

30

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

Generics in Java se implementa a través de type erasure por el compilador, lo que significa que la comprobación de tipos se produce en tiempo de compilación, y la información de tipo se elimina. Este enfoque fue tomada para mantener el código heredado compatible con código usando nuevos genéricos:

De Los Tutoriales de Java, Generics: Type Erasure:

Cuando se crea una instancia de un tipo genérico, el compilador traduce esos tipos por 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 escribe argumentos dentro de una clase o método . La eliminación de tipos habilita las aplicaciones Java que usan genéricos a mantienen la compatibilidad binaria con Se crearon bibliotecas y aplicaciones Java que antes que los genéricos.

Sin embargo, con generics in C# (.NET), no hay ningún tipo de borrado por el compilador, y los controles de tipo se llevan a cabo durante la ejecución. Esto tiene sus beneficios de que la información de tipo se conserva en el código compilado.

De Wikipedia:

Esta opción de diseño se aprovecha para proporcionan funcionalidades adicionales, tales como permitir la reflexión con preservación de tipos genéricos, así como aliviar algunas de las limitaciones de borrado (tales como incapaz de crear matrices genéricas). Este también significa que no hay rendimiento afectado por los modelos de tiempo de ejecución y conversiones de box normalmente caras.

En lugar de decir ".NET genéricos es mejor que los genéricos de Java", uno debe considerar 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.

+0

@Tom ¿Qué significa "Inmunidad del análisis"? – LamonteCristo

+7

Significa que, sí, puede decir "Los genéricos de .NET son mejores que los genéricos de Java". Java debería haber adoptado el enfoque de hacer un cambio radical e implementar correctamente los medicamentos genéricos cuando tenían la oportunidad de hacerlo. – Mike

+2

La "compatibilidad con versiones anteriores" es incorrecta, ambas son compatibles con versiones anteriores. Fue hecho para "Compatibilidad de migración". – kervin

4

encuentra también this conversación con Anders Hejlsberg que puede ser interesante también. Para resumir los puntos que Anders Hejlsberg hizo con algunas notas adicionales: Se realizaron genéricos de Java para una máxima compatibilidad con JVM que llevó a algunas cosas extrañas en comparación con la aplicación existente que se ven en C#:

  • Tipo de aplicación fuerzas de borrado para representar cada valor genérico parametrizado como Object. Mientras compilador proporciona moldes automáticos entre Object y el tipo más específico, no eliminar los efectos negativos de los modelos tipo y el boxeo en el rendimiento (por ejemplo Object se convierte al tipo específico MyClass o int tuvo que ser encajonado en Integer, lo que sería aún más serio para C# /. NET si siguieron el enfoque de borrado de tipo debido a los tipos de valores definidos por el usuario). Como Anders dijo: "usted no recibe ninguna de la eficiencia de la ejecución" (que los genéricos reificadas permiten en C#)

  • Tipo borrado hace que la información disponible en tiempo de compilación en tiempo de ejecución no es accesible. Algo que solía ser List<Integer> se convierte simplemente en List sin posibilidad 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. Más reciente SO answer 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 colecció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 desadaptación en List<Double> en comparación con List<Integer> en estas situaciones

Pero +1 en la respuesta que enlaza con blog post de Jonathan Pryor.