2010-01-25 16 views
27

En el muy alto nivel, sé que tenemos que "envolver" los tipos de datos primitivos, como int y char, utilizando sus respectivas clases contenedoras para usarlos dentro de las colecciones Java. Me gustaría entender cómo funcionan las colecciones Java. en el nivel bajo, preguntando: "¿por qué tenemos que envolver los tipos de datos primitivos como objetos para poder usarlos en las colecciones?" Le agradezco de antemano su ayuda.Java: ¿Por qué son necesarias las clases de contenedor?

+0

posible duplicado de [¿Por qué hay clases contenedoras en Java?] (Http://stackoverflow.com/questions/3579035/why-are-there-wrapper-classes -in-java) – nbro

Respuesta

18

En el nivel de la máquina virtual, es porque los tipos primitivos se representan de forma muy diferente en la memoria en comparación con los tipos de referencia como java.lang.Object y sus tipos derivados. Primitive int en Java, por ejemplo, tiene solo 4 bytes en la memoria, mientras que un objeto ocupa al menos 8 bytes por sí mismo, más otros 4 bytes para hacer referencia a él. Tal diseño es un simple reflejo del hecho de que las CPU pueden tratar tipos primitivos de manera mucho más eficiente.

Así que una respuesta a su pregunta "por qué son necesarios los tipos de envoltura" se debe a la mejora del rendimiento que permite.

Pero para los programadores, tal distinción agrega una carga cognitiva indeseable (por ejemplo, no se puede usar int y float en colecciones). De hecho, es posible hacer un diseño de lenguaje ocultando esa distinción --- muchos lenguajes de scripting haz esto, y CLR hace eso. A partir de 1.5, Java también lo hace. Esto se logra al permitir que el compilador inserte silenciosamente la conversión necesaria entre la representación primitiva y la representación de Objeto (que comúnmente se conoce como boxeo/unboxing).)

Así que otra respuesta a su pregunta es: "no, no la necesitamos", porque el compilador lo hace automáticamente, y en cierta medida puede olvidar lo que sucede detrás de la escena.

+1

¿Puede explicar cómo JVM almacena los tipos primitivos y los tipos de referencia en la memoria? –

+2

@Midnight Blue - Lea la primera respuesta (por Jon Skeet) aquí: http://stackoverflow.com/questions/2099695/java-array-is-stored-in-stack-or-heap. Explica más sobre cómo se almacenan las cosas en la JVM y cuándo. –

+0

@Justin N. - Gracias por el enlace –

31

Debido a que las colecciones de Java solo pueden almacenar referencias a objetos (por lo que debe colocar primitivas en el cuadro para almacenarlas en colecciones).

Lea este artículo breve en Autoboxing para obtener más información.

Si desea que los detalles Nitty Gritty, que prácticamente se reduce a lo siguiente:

Primitives locales se almacenan en la pila. Las colecciones almacenan sus valores a través de una referencia a la ubicación de memoria de un Objeto en el Heap. Para obtener esa referencia para una primitiva local, tiene que insertar el valor (tomar el valor en la pila y envolverlo para almacenarlo en el montón).

3

No se puede hacer referencia a los tipos de datos primitivos como direcciones de memoria. Es por eso que necesitamos envolturas que sirvan como marcadores de posición para valores primitivos. Estos valores pueden ser mutados y accedidos, reorganizados, ordenados o aleatorizados.

+1

¿Eh? Java no tiene punteros. – BalusC

+1

Usted escribió: "Estos valores pueden ser mutados". Esto no es cierto para las envolturas de objetos primitivos en Java. Todos son inmutables. – Asaph

+0

Una referencia básicamente es un puntero, solo un poco más restrictivo. En mi opinión, deberían haberlo llamado puntero en lugar de referencia, ya que el término "referencia" es muy engañoso. – helpermethod

1

Bueno, la razón es porque las colecciones de Java no diferencian entre primitivo y Objeto. Los procesa todos como Objeto y, por lo tanto, necesitará un contenedor. Puedes construir fácilmente tu propia clase de colección que no necesita envoltorio, pero al final, tendrás que compilar una para cada tipo char, int, float, double, etc. multiplica por los tipos de colecciones (Set, Map, Lista, + su implementación).

¿Te imaginas lo aburrido que es eso?

Y la realidad es que el rendimiento que aporta el uso de envoltorios es casi insignificante para la mayoría de las aplicaciones. Sin embargo, si necesita un rendimiento muy alto, algunas bibliotecas para colecciones primitivas también están disponibles (por ejemplo, http://www.joda.org/joda-primitives/)

+0

Las colecciones se diferencian muy bien: funcionan bastante bien con los objetos y te abofetean con errores de compilación si pruebas con primitivos Java. –

4

Para almacenar los valores del tipo primitivo en clases de recopilación, se requiere clasificación de Contenedor.

1

Colección utiliza genéricos como base. The Collection Framework está diseñado para recopilar, almacenar y manipular los datos de cualquier clase. Entonces usa un tipo genérico. Al usar Generics, es capaz de almacenar los datos de CUALQUIER CLASE cuyo nombre especifique en su declaración.

Ahora tenemos varios escenarios en los que queremos almacenar los datos primitivos de la misma manera en que funciona la colección. No tenemos forma de almacenar datos primitivos usando clases de Colección como ArrayList, HashSet, etc. porque las clases de Colección solo pueden almacenar objetos. Entonces, para almacenar tipos primitivos en Collection, se nos proporcionan clases de contenedor.

0

Las clases de envoltorio proporcionan métodos útiles relacionados con los tipos de datos correspondientes que puede utilizar en ciertos casos.

Un ejemplo simple. Considere esto,

Integer x=new Integer(10); 
//to get the byte value of 10 
x.byteValue(); 

//but you can't do this, 
int x=10; 
x.byteValue(); //Wrong! 

¿Puede entender el punto?

0

Si se sabe que una variable contiene un patrón de bits específico que representa null o información que puede usarse para localizar un encabezado de objeto Java Virtual Machine, y si el método para leer un encabezado de objeto dado una referencia atrapará si dado el patrón de bits asociado con null, la JVM puede acceder al objeto identificado por la variable en el supuesto de que exista uno. Si una variable podría contener algo que no era una referencia válida pero no era el patrón de bits específico null, cualquier código que intentara usar esa variable tendría que verificar primero si identificaba un objeto. Eso ralentizaría mucho la JVM.

Si Object deriva de Anything, y los objetos clase derivada de Object, pero primitivos heredados de una clase diferente derivado de Anything, a continuación, en una aplicación de 64 bits que podría ser práctico para decir que aproximadamente 3/4 de la posible bits los patrones representarían double valores por debajo de 2^512, 1/8 de ellos para representar long valores en el rango +/- 1,152,921,504,606,846,975, algunos miles de millones para representar cualquier valor posible de cualquier primitve y 1/256 para identificar objetos. Muchos tipos de operaciones en cosas del tipo Anything serían más lentas que con el tipo Object, pero tales operaciones no serían terriblemente frecuentes; la mayoría del código terminaría fundiendo Anything en algún tipo más específico antes de intentar trabajar con él; el tipo real almacenado en Anything debería verificarse antes del lanzamiento, pero no después de que se haya realizado el lanzamiento. Sin una distinción entre una variable que contiene una referencia a un tipo de montón, sin embargo, frente a una que tenga "nada", no habría forma de evitar que la sobrecarga se extienda considerablemente más allá de lo que debería o debería.

0

Al igual que la clase String, los Wrappers proporcionan funcionalidad adicional y permiten al programador hacer un poco más con el proceso de almacenamiento de datos. Así que en la misma forma de utilizar la clase String como ....

String uglyString = "fUbAr"; String myStr = uglyString.toLower();

así también, que pueden con la envoltura. Idea similar

Esto se suma a la cuestión de tipeo de colecciones/genéricos mencionados anteriormente por Bharat.

0

Lea todas las respuestas, pero ninguna de ellas realmente lo explica simplemente en términos sencillos.

A envoltura envolturas de clase (encierra) alrededor de un tipo de datos (puede ser cualquier tipo de datos primitivos como int, char, byte, de largo) y lo convierte en un objeto.

Estas son algunas de las razones por qué se necesitan clases de contenedor:

  1. Permite null valores.
  2. Puede ser utilizado en la recogida tal como List, Map, etc.
  3. Se puede utilizar en métodos que acepta argumentos de Object tipo.
  4. se pueden crear objetos utilizando como new ClassName() al igual que otros objetos:

    Integer wrapperInt = new Integer("10"); 
    
  5. pone a disposición todas las funciones que Object clase tiene como clone(), equals(), hashCode(), etc. toString()

clases Wrapper se puede crear de dos maneras:

  1. Usando constructor:

    Integer i = new Integer("1"); //new object is created 
    
  2. Usando valueOf() operadores estáticas:

    Integer i = Integer.valueOf("100"); //100 is stored in variable 
    

Se aconseja utilizar la segunda forma de crear clases contenedoras, ya que toma menos memoria como un nuevo objeto es no creado.

0

porque int no pertenece a ninguna clase. convertimos el tipo de datos (int) al objeto (Interger)

Cuestiones relacionadas