¿Por qué utilizamos el autoboxing y unboxing en Java?

81

Autoboxing es la conversión automática que realiza el compilador de Java entre los tipos primitivos y sus clases de envoltura de objetos correspondientes. Por ejemplo, convertir un int en un Integer, un double en un Double, y así sucesivamente. Si la conversión es al revés, esto se llama unboxing.

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

Theodoros Chatzigiannakis
fuente
1
Básicamente para genéricos ..
nachokk
3
Integertener parseIntmétodo. intno tiene. :)
Vishal Zanzrukia
@VishalZanzrukia ¿Entonces, solo para obtener más funcionalidad?
12
Puedes tener List<Integer>, pero no puedes tener List<int>.
Vishal Zanzrukia
Sí ... exactamente ... para obtener más funciones
Vishal Zanzrukia

Respuestas:

173

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 coma 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 se implementan normalmente como punteros (o algo muy similar a punteros) en muchos idiomas. Estas cosas suelen tener el mismo tamaño, independientemente de los tamaños de los casos se refieren a ( Object, String, Integer, etc.).

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 una instancia de otro tipo relacionado (use a Stringcomo an 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 razón) 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 tipo

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(producir un tipo concreto List<Object> ), String( List<String>), Integer( List<Integer>) y así sucesivamente.

Los tipos genéricos son mucho más complicados que los no genéricos. Cuando se introdujeron en Java (después de su lanzamiento inicial), para evitar hacer 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>son, de hecho, compilados en (el equivalente binario de) List<Object>(para otros tipos, el límite puede ser diferente de Object, pero entiendes el punto). La aridad genérica y la información de los parámetros de tipo se pierden en este proceso , por lo que lo llamamos borrado de tipo .

Poniendo los dos juntos

Ahora el problema es la combinación de las realidades anteriores: si se List<T>convierte List<Object>en todos los casos, Tsiempre debe ser un tipo al que se pueda asignar directamenteObject . No se puede permitir nada más. Dado que, como hemos dicho antes, int, floaty doubleno son intercambiables con Object, no puede haber una List<int>, List<float>o List<double>(a menos que una aplicación mucho más complicado de los genéricos existía en la JVM).

Pero Java tipos de ofertas como Integer, Floaty Doubleque envuelven estas primitivas en las instancias de clase, por lo que efectivamente sustituibles como Object, por lo tanto permitiendo que los tipos genéricos de forma indirecta trabajo con las primitivas así (porque se puede tener List<Integer>, List<Float>, List<Double>y así sucesivamente).

El proceso de crear un Integerdesde un int, un Floatdesde un floaty así sucesivamente, se llama boxeo . Lo contrario se llama unboxing . Debido a que tener que encuadrar primitivas cada vez que desee usarlas Objectes un inconveniente, hay casos en los que el lenguaje lo hace automáticamente, lo que se llama autoencuadre .

Theodoros Chatzigiannakis
fuente
Según su explicación, necesitamos estas clases Integer, String, ... para implementar genéricos. ¿Hay alguna otra razon?
Bishwas Mishra
1
@BishwasMishra Los tenemos para que podamos usar estos valores como Objectinstancias. Los genéricos a través del borrado de tipo es una aplicación de eso.
Theodoros Chatzigiannakis
16

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

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

Es necesario que los programadores sean fáciles de escribir código directamente y JVM se encargará del Boxing y Unboxing.

Auto Boxing también es ú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 de envoltura

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

Uso de clases de envoltura

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 opuesto a Auto Boxing, donde convertimos el objeto de la clase contenedora de nuevo a su tipo primitivo. Esto lo hace automáticamente JVM para que podamos usar las clases contenedoras para ciertas operaciones y luego convertirlas de nuevo en tipos primitivos, ya que las primitivas resultan en un procesamiento más rápido. Por ejemplo :

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

En el caso de las colecciones que funcionan con objetos, solo se utiliza el desempaquetado 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
fuente
4

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

Los tipos primitivos int, boolean, doubleson datos inmediatos, mientras que Objects 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 contenedores de objetos Integer, Doubley otros, se introduciría una indirección, una referencia a alguna instancia de Integer / Double en la memoria del montón.

¿Por qué se necesita el boxeo?

Ésa es una cuestión de alcance relativo. En un futuro java, se planea poder tener un ArrayList<int>tipo primitivo de elevación.

Respuesta: Por ahora, una ArrayList solo funciona para Object, 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 objetos secundarios. Entonces, si uno quería una ArrayList de valores de punto flotante, era necesario envolver un doble en un objeto Double.

Aquí Java se diferencia del C ++ tradicional con 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 ArrayList.class, sin necesidad de un nuevo producto compilado para cada tipo de parámetro.

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

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

Joop Eggen
fuente
4

A partir de JDK 5, Java ha agregado dos funciones importantes: autoboxing y autounboxing. AutoBoxing es el proceso para el cual un tipo primitivo se encapsula automáticamente en el contenedor equivalente siempre que se necesita tal objeto. No tiene que 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 tipo 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 boxeo y unboxing de valores manualmente. También es útil evitar errores . También es muy importante para los genéricos , que solo operan con objetos. Por último, el autoboxing facilita el trabajo con el marco de colecciones .

Amarildo
fuente
2

¿Por qué tenemos (des) boxeo?

para hacer que escribir código donde mezclamos primitivas y sus alternativas orientadas a objetos (OO) sea más cómodo / menos detallado.

¿Por qué tenemos primitivas y sus alternativas OO?

los tipos primitivos no son clases (a diferencia de C #), por lo que no son subclases de Objecty no se pueden anular.

tenemos primitivas como intpor razones de rendimiento, y las Objectalternativas como Integerpor los beneficios de la programación OO, y como punto menor, para tener una buena ubicación para las constantes y métodos de utilidad (Integer.MAX_VALUE yInteger.toString(int) ).

Los beneficios de OO son visibles más fácilmente con Generics ( List<Integer>), pero no se limitan a eso, por ejemplo:

Number getMeSome(boolean wantInt) {

    if (wantInt) {
        return Integer.MAX_VALUE;
    } else {
        return Long.MAX_VALUE;
    }
}
hoijui
fuente
1

Algunas estructuras de datos solo pueden aceptar objetos, no tipos primitivos.

Ejemplo: la clave en un HashMap.

Consulte esta pregunta para obtener más información: HashMap e int como clave

Hay otras buenas razones, como un campo "int" en una base de datos, que también podría ser NULL. Un int en Java no puede ser nulo; una referencia entera puede. El empaquetado automático y el desempaquetado proporcionan la posibilidad de evitar escribir código extraño en las conversiones de ida y vuelta.

Gabriel
fuente
0

Porque son de diferentes tipos y por comodidad. El rendimiento es probablemente la razón para tener tipos primitivos.

Scott Hunter
fuente
0

ArrayList no admite tipos primitivos, solo admite clases. pero necesitamos usar tipos primitivos, por ejemplo, int, double, etc.

ArrayList<String> strArrayList = new ArrayList<String>(); // is accepted.

ArrayList<int> intArrayList = new ArrayList<int>(); // not accepted.

La clase Integer envuelve un valor del tipo primitivo int en un objeto, por lo que se acepta el código siguiente.

ArrayList<Integer> intArrayList = new ArrayList<Integer>(); // is accepted.

podemos agregar un valor con el método add (value). Para agregar un valor de cadena, diga "Hola" en el código strArrayList es solo

strArrayList.add("Hello");  

y agregue un valor int digamos 54 podemos escribir

intArrayList.add(54);

pero cuando escribimos intArrayList.add (54); compilador convertir a la siguiente línea

intArrayList.add(Integer.valueOf(54)); 

Como intArrayList.add (54) es fácil y más aceptable desde el lado del usuario, el compilador hace el trabajo difícil que es `intArrayList.add(Integer.valueOf(54)); es autoBoxing.

De manera similar, para recuperar el valor, simplemente escribimos intArrayList.get (0) y el compilador convierte a lo <code>intArrayList.get(0).intValue();que es autoUnboxing.

Chhalma Sultana Chhaya
fuente
0

Autoboxing: conversión de un valor primitivo en un objeto de la clase contenedora correspondiente.

Unboxing: conversión de un objeto de tipo contenedor a su valor primitivo correspondiente

// Java program to illustrate the concept 
// of Autoboxing and Unboxing 
import java.io.*; 

class GFG 
{ 
    public static void main (String[] args) 
    { 
        // creating an Integer Object 
        // with value 10. 
        Integer i = new Integer(10); 

        // unboxing the Object 
        int i1 = i; 

        System.out.println("Value of i: " + i); 
        System.out.println("Value of i1: " + i1); 

        //Autoboxing of char 
        Character gfg = 'a'; 

        // Auto-unboxing of Character 
        char ch = gfg; 
        System.out.println("Value of ch: " + ch); 
        System.out.println("Value of gfg: " + gfg); 

    } 
} 
Yash Patel
fuente