¿Por qué utilizamos autoboxing y unboxing en Java?

Resuelto asked hace 9 años • 10 respuestas

Autoboxing es la conversión automática que realiza el compilador de Java entre los tipos primitivos y sus correspondientes clases contenedoras de objetos. Por ejemplo, convertir un int en un Entero, un doble en un Doble, etc. Si la conversión se realiza al revés, esto se llama unboxing.

Entonces, ¿por qué lo necesitamos y por qué utilizamos autoboxing y unboxing en Java?

 avatar Dec 25 '14 19:12
Aceptado

Se requiere algo de contexto para comprender completamente la razón principal detrás de esto.

Primitivos versus clases

Las variables primitivas en Java contienen valores (un número entero, un número binario de punto flotante de doble precisión, etc.). Debido a que estos valores pueden tener diferentes longitudes , las variables que los contienen también pueden tener diferentes longitudes (considere floatversus double).

Por otro lado, las variables de clase contienen referencias a instancias. Las referencias normalmente se implementan como punteros (o algo muy similar a los punteros) en muchos idiomas. Estas cosas suelen tener el mismo tamaño, independientemente del tamaño de las instancias a las que hacen referencia ( ,,, Objectetc. ).StringInteger

Esta propiedad de las variables de clase hace que las referencias que contienen sean intercambiables (hasta cierto punto). Esto nos permite hacer lo que llamamos sustitución : en términos generales, usar una instancia de un tipo particular como instancia de otro tipo relacionado (use a Stringcomo Object, por ejemplo).

Las variables primitivas no son intercambiables de la misma manera, ni entre sí ni con Object. La razón más obvia de esto (pero no la única) es su diferencia de tamaño. Esto hace que los tipos primitivos sean inconvenientes a este respecto, pero aún los necesitamos en el lenguaje (por razones que se reducen principalmente al rendimiento).

Genéricos y borrado de tipos

Los tipos genéricos son tipos con uno o más parámetros de tipo (el número exacto se llama aridad genérica ). Por ejemplo, la definición de tipo genérico List<T> tiene un parámetro de tipo T, que puede ser Object(produciendo un tipo concreto List<Object> ), String( List<String>), Integer( List<Integer>), etc.

Los tipos genéricos son mucho más complicados que los no genéricos. Cuando conocieron Java (después de su lanzamiento inicial), para evitar realizar cambios radicales en la JVM y posiblemente romper la compatibilidad con binarios más antiguos, los creadores de Java decidieron implementar tipos genéricos de la manera menos invasiva: todos los tipos concretos de List<T>de hecho, están compilados en (el equivalente binario de) List<Object>(para otros tipos, el límite puede ser algo distinto a Object, pero ya entiendes el punto). En este proceso se pierde la información genérica y de parámetros de tipo , por lo que lo llamamos borrado de tipo .

Juntando los dos

Ahora el problema es la combinación de las realidades anteriores: si List<T>se convierte List<Object>en todos los casos, entonces Tsiempre debe haber un tipo al que se pueda asignar directamenteObject . No se puede permitir nada más. Dado que, como dijimos antes, inty floatno doubleson intercambiables con Object, no puede haber un List<int>, List<float>o List<double>(a menos que exista una implementación significativamente más complicada de genéricos en la JVM).

Pero Java ofrece tipos como Integer, Floaty Doubleque envuelven estas primitivas en instancias de clase, haciéndolas efectivamente sustituibles como Object, permitiendo así que los tipos genéricos también funcionen indirectamente con las primitivas (porque puedes tener List<Integer>, List<Float>, List<Double>etc.).

El proceso de crear un Integera partir de un int, un Floata partir de un float, etc., se llama boxeo . Lo contrario se llama unboxing . Debido a que tener que encuadrar las primitivas cada vez que desea usarlas Objectes un inconveniente, hay casos en los que el lenguaje lo hace automáticamente; eso se llama autoboxing .

Theodoros Chatzigiannakis avatar Dec 25 '2014 13:12 Theodoros Chatzigiannakis

Auto Boxing se utiliza para convertir tipos de datos primitivos en sus objetos de clase contenedora. La clase contenedora proporciona una amplia gama de funciones que se realizarán en los tipos primitivos. El ejemplo más común es:

int a = 56;
Integer i = a; // Auto Boxing

Es necesario porque los programadores pueden escribir código directamente y JVM se encargará del Boxing y Unboxing.

Auto Boxing también resulta útil cuando trabajamos con tipos java.util.Collection. Cuando queremos crear una Colección de tipos primitivos, no podemos crear directamente una Colección de un tipo primitivo, podemos crear una Colección solo de Objetos. Por ejemplo :

ArrayList<int> al = new ArrayList<int>(); // not supported 

ArrayList<Integer> al = new ArrayList<Integer>(); // supported 
al.add(45); //auto Boxing 

Clases contenedoras

Cada uno de los 8 tipos primitivos de Java (byte, short, int, float, char, double, boolean, long) tiene una clase Wrapper separada asociada a ellos. Estas clases Wrapper tienen métodos predefinidos para realizar operaciones útiles en tipos de datos primitivos.

Uso de clases contenedoras

String s = "45";
int a = Integer.parseInt(s); // sets the value of a to 45.

Hay muchas funciones útiles que proporcionan las clases Wrapper. Consulte los documentos de Java aquí

Unboxing es lo opuesto a Auto Boxing, donde convertimos el objeto de clase contenedora a su tipo primitivo. JVM hace esto automáticamente para que podamos usar las clases contenedoras para determinadas operaciones y luego convertirlas nuevamente a tipos primitivos, ya que las primitivas dan como resultado un procesamiento más rápido. Por ejemplo :

Integer s = 45;
int a = s; auto UnBoxing;

En el caso de colecciones que funcionan con objetos, solo se utiliza el unboxing automático. Así es cómo :

ArrayList<Integer> al = new ArrayList<Integer>();
al.add(45);

int a = al.get(0); // returns the object of Integer . Automatically Unboxed . 
varun avatar Dec 25 '2014 13:12 varun

Los tipos primitivos (no objeto) tienen su justificación en la eficiencia.

Los tipos primitivos int, boolean, doubleson datos inmediatos, mientras que Objectlos s son referencias. Por lo tanto, campos (o variables)

int i;
double x;
Object s;

¿Necesitaría memoria local 4+8+8? donde para el objeto solo se almacena la referencia (dirección) a la memoria.

Usando los envoltorios de objetos Integer, Doubley otros, se introduciría una dirección indirecta, una referencia a alguna instancia entera/doble en la memoria del montón.

¿Por qué es necesario el boxeo?

Ésta es una cuestión de alcance relativo. En un futuro Java está previsto poder tener un ArrayList<int>, eliminando tipos primitivos.

Respuesta: Por ahora, ArrayList solo funciona para Objetos, reservando espacio para una referencia de objeto y administrando la recolección de basura de la misma manera. Por tanto, los tipos genéricos son hijos de objetos. Entonces, si uno quería una ArrayList de valores de punto flotante, necesitaba envolver un doble en un objeto Doble.

Aquí Java se diferencia del C++ tradicional por sus plantillas: las clases de C++ vector<string>, vector<int>crearían dos productos de compilación. El diseño de Java optó por tener una clase ArrayList.class, sin necesitar para cada tipo de parámetro un nuevo producto compilado.

Entonces, sin encajonar el Objeto, uno necesitaría compilar clases para cada aparición de un tipo de parámetro. En concreto: cada colección o clase contenedora necesitaría una versión para Objeto, int, double, boolean. La versión de Object manejaría todas las clases secundarias.

De hecho, la necesidad de dicha diversificación ya existía en Java SE para IntBuffer, CharBuffer, DoubleBuffer, ... que operan en int, char, double. Se resolvió de forma hacky generando estas fuentes a partir de una común.

Joop Eggen avatar Dec 25 '2014 14:12 Joop Eggen

A partir de JDK 5, Java ha agregado dos funciones importantes: autoboxing y autounboxing. AutoBoxing es el proceso por el cual un tipo primitivo se encapsula automáticamente en el contenedor equivalente siempre que dicho objeto sea necesario. No es necesario construir explícitamente un objeto. El desempaquetado automático es el proceso mediante el cual el valor de un objeto encapsulado se extrae automáticamente de un contenedor de tipos cuando se requiere su valor. No es necesario llamar a un método como intValue() o doubleValue() .

La adición de autoboxing y auto-unboxing simplifica enormemente los algoritmos de escritura , eliminando el cebo de boxing y unboxing manual de valores. También es útil para evitar errores . También es muy importante para los genéricos , que sólo operan sobre objetos. Por último, el autoboxing facilita el trabajo con Collections Framework .

Amarildo avatar Jul 02 '2017 20:07 Amarildo