2010-03-24 16 views
87

Las colecciones de Java solo almacenan Objetos, no tipos primitivos; sin embargo, podemos almacenar las clases de envoltura.¿Por qué Java Collections no almacena directamente tipos de primitivos?

¿Por qué esta restricción?

+2

Esta restricción es mala cuando se trata de primitivas y se desean utilizar colas para enviar y las tasas de envío son muy rápidas. Estoy lidiando con ese problema en este momento de autoboxing que toma demasiado tiempo. – JPM

Respuesta

73

Fue una decisión de diseño de Java, y que algunos consideran un error. Los contenedores quieren Objetos y primitivos no derivan de Objeto.

Este es un lugar que los diseñadores de .NET aprendieron de la JVM e implementaron tipos de valores y genéricos tales que el boxeo se elimina en muchos casos. En CLR, los contenedores genéricos pueden almacenar tipos de valor como parte de la estructura del contenedor subyacente.

Java optó por agregar compatibilidad genérica al 100% en el compilador sin soporte de la JVM. La JVM es lo que es, no admite un objeto "no objeto". Los genéricos de Java le permiten pretender que no existe un contenedor, pero aún así paga el precio de rendimiento del boxeo. Esto es IMPORTANTE para ciertas clases de programas.

El boxeo es un compromiso técnico, y creo que es el detalle de implementación que se filtra en el idioma. Autoboxing es un buen azúcar sintáctico, pero sigue siendo una penalización de rendimiento. En todo caso, me gustaría que el compilador me advierta cuando se autocarta. (Por lo que sé, puede que ahora, escribí esta respuesta en 2010).

Una buena explicación de SO sobre el boxeo: Why do some languages need Boxing and Unboxing?

y la crítica de los genéricos de Java: Why do some claim that Java's implementation of generics is bad?

En defensa de Java, es fácil mirar hacia atrás y criticar. La JVM ha resistido la prueba del tiempo y es un buen diseño en muchos aspectos.

+0

+1 para tipos de valores. – Thilo

+5

No es un error, una compensación cuidadosamente elegida que creo que ha servido a Java muy bien. – DJClayworth

+12

Fue un error suficiente que .NET aprendió de él e implementó el autoboxing desde el principio, y genéricos en el nivel VM sin la sobrecarga del boxeo. El propio intento de Java por una corrección fue solo una solución de nivel de sintaxis que todavía sufre el golpe de rendimiento del autoboxing frente a ningún boxeo. La implementación de Java ha mostrado un rendimiento deficiente con grandes estructuras de datos. – codenheim

7

Existe el concepto de auto-boxing y auto-unboxing. Si intenta almacenar un int en un List<Integer> el compilador de Java lo convertirá automáticamente a un Integer.

+0

Creo que se agregó después de Java 1.5 ... ¿correcto? – JavaUser

+1

Autoboxing se introdujo en Java 1.5 junto con Generics. – Jeremy

+1

Pero es una cosa de tiempo de compilación; sintaxis azúcar sin beneficio de rendimiento. El compilador Java se autocaptura, por lo tanto, la penalización del rendimiento en comparación con las implementaciones de máquinas virtuales, como .NET, cuyos genéricos no incluyen el boxeo. – codenheim

3

No es realmente una limitación ¿verdad?

Considere si desea crear una colección que almacena valores primitivos. ¿Cómo escribirías una colección que pueda almacenar int, float o char? Lo más probable es que termines con varias colecciones, por lo que necesitarás una intlist y una charlist, etc.

Aprovechando la naturaleza orientada a objetos de Java cuando escribes una clase de colección, puede almacenar cualquier objeto por lo que solo necesitas uno clase de colección Esta idea, polimorfismo, es muy poderosa y simplifica enormemente el diseño de las bibliotecas.

+6

"¿Cómo escribirías una colección que pueda almacenar int, o float o char?"- Con genéricos/plantillas correctamente implementados como otros lenguajes que no pagan la pena de pretender que todo es un objeto. – codenheim

+0

Casi nunca en seis años de Java he querido almacenar una colección de primitivos. Incluso en los pocos casos en que podría he querido el tiempo extra y los costos de espacio de usar los objetos de referencia han sido insignificantes. En particular, creo que muchas personas piensan que quieren Map , olvidando que una matriz hará ese truco muy bien. – DJClayworth

+0

@DJClayworth Eso solo funciona bien si los valores clave no son escasos. Por supuesto, podría usar una matriz auxiliar para realizar un seguimiento de las claves, pero eso tiene sus propios problemas: un acceso relativamente eficiente requeriría mantener ambas matrices ordenadas según el orden de las claves para permitir la búsqueda binaria. lo que a su vez haría que la inserción y eliminación fueran ineficientes a menos que la inserción/eliminación esté modelada de manera tal que los elementos insertados terminen en w aquí, un elemento previamente eliminado y/o algunos buffers están intercalados en las matrices, etc. Hay recursos disponibles, pero sería bueno tenerlos en Java. – JAB

9

Es una combinación de dos hechos:

  • tipos primitivos de Java no se Referencia tipos (por ejemplo, un int no es una Object)
  • Java hace genéricos utilizando el tipo-borrado de los tipos de referencia (por ejemplo, un List<?> es realmente un List<Object> en tiempo de ejecución)

Dado que ambos son verdaderos, las colecciones Java genéricas no pueden almacenar tipos primitivos directamente. Para mayor comodidad, se introduce el autoboxing para permitir que los tipos primitivos se incluyan automáticamente en cuadros como tipos de referencia. Sin embargo, no se equivoque, las colecciones aún almacenan referencias de objetos.

¿Se pudo haber evitado esto? Quizás.

  • Si un int es un Object, entonces no hay necesidad de que los tipos de cuadros en absoluto.
  • Si los genéricos no se realizan con borrado de tipo, las primitivas podrían haberse utilizado para los parámetros de tipo.
14

Facilita la implementación. Como las primitivas de Java no se consideran Objetos, necesitaría crear una clase de colección separada para cada una de estas primitivas (sin código de plantilla para compartir).

Puede hacerlo, por supuesto, simplemente vea GNU Trove, Apache Commons Primitives o HPPC.

A menos que tenga grandes colecciones, la sobrecarga de las envolturas no es suficiente para que las personas se interesen (y cuando realmente tiene grandes colecciones primitivas, puede que desee dedicar el esfuerzo de usar/construir un estructura de datos para ellos).

+0

gracias por las primitivas de apache commons y gnu trove mentions. Enlaces útiles –

0

Creo que podríamos ver el progreso en este espacio en el JDK posiblemente en Java 10 basado en este JEP - http://openjdk.java.net/jeps/218.

Si desea evitar las primitivas del boxeo en las colecciones de hoy, existen varias alternativas de terceros. Además de las opciones de terceros mencionadas anteriormente, también hay Eclipse Collections, FastUtil y Koloboke.

Una comparación de mapas primitivos también se publicó hace un tiempo con el título: Descripción general de HashMap: JDK, FastUtil, Goldman Sachs, HPPC, Koloboke, Trove. La biblioteca de GS Collections (Goldman Sachs) se migró a la Fundación Eclipse y ahora es Eclipse Collections.

Cuestiones relacionadas