En informática , el boxing (también conocido como wrapping) es la transformación que consiste en colocar un tipo primitivo dentro de un objeto para que el valor pueda usarse como referencia . El unboxing es la transformación inversa que consiste en extraer el valor primitivo de su objeto contenedor. El autoboxing es el término que se utiliza para aplicar automáticamente transformaciones de boxing y/o unboxing según sea necesario.
El uso más destacado del boxing es en Java , donde hay una distinción entre los tipos de referencia y de valor por razones como la eficiencia en tiempo de ejecución y cuestiones de sintaxis y semánticas. En Java, a LinkedList
solo puede almacenar valores de tipo Object
. Se podría desear tener a LinkedList
de int
, pero esto no es directamente posible. En su lugar, Java define clases contenedoras primitivas correspondientes a cada tipo primitivo : Integer
and int
, Character
and char
, Float
and float
, etc. A continuación, se puede definir a LinkedList
utilizando el tipo boxed Integer
e insertar int
valores en la lista boxeándolos como Integer
objetos. (Usando tipos genéricos parametrizados introducidos en J2SE 5.0, este tipo se representa como .)LinkedList<Integer>
Por otro lado, C# no tiene clases contenedoras primitivas, pero permite el boxing de cualquier tipo de valor, devolviendo una Object
referencia genérica. En Objective-C , cualquier valor primitivo puede tener como prefijo a @
para formar un NSNumber
a partir de él (por ejemplo, @123
o ). Esto permite agregarlos en cualquiera de las colecciones estándar, como un .@(123)
NSArray
Haskell tiene poca o ninguna noción de tipo de referencia , pero aún usa el término "en caja" para la representación uniforme de puntero a unión etiquetada del sistema de tiempo de ejecución . [1]
El objeto en caja siempre es una copia del objeto de valor y, por lo general, es inmutable . Al desempaquetar el objeto, también se devuelve una copia del valor almacenado. El encasillado y desempaquetado repetidos de objetos pueden tener un impacto grave en el rendimiento, porque el encasillado asigna dinámicamente nuevos objetos y el desempaquetado (si el valor en caja ya no se usa) los hace elegibles para la recolección de elementos no utilizados . Sin embargo, los recolectores de elementos no utilizados modernos, como el recolector de elementos no utilizados Java HotSpot predeterminado, pueden recolectar objetos de corta duración de manera más eficiente, por lo que si los objetos en caja tienen una vida útil corta, el impacto en el rendimiento puede no ser grave.
En algunos lenguajes, existe una equivalencia directa entre un tipo primitivo no encapsulado y una referencia a un tipo de objeto encapsulado e inmutable. De hecho, es posible sustituir todos los tipos primitivos de un programa por tipos de objeto encapsulados. Mientras que la asignación de un tipo primitivo a otro copiará su valor, la asignación de una referencia a un objeto encapsulado a otro copiará el valor de referencia para hacer referencia al mismo objeto que la primera referencia. Sin embargo, esto no causará ningún problema, porque los objetos son inmutables, por lo que semánticamente no hay ninguna diferencia real entre dos referencias al mismo objeto o a objetos diferentes (a menos que se observe la igualdad física). Para todas las operaciones que no sean de asignación, como aritmética, comparación y operadores lógicos, se puede desencapsular el tipo encapsulado, realizar la operación y volver a encapsular el resultado según sea necesario. Por lo tanto, es posible no almacenar tipos primitivos en absoluto.
El término "autoboxing" se utiliza para obtener un tipo de referencia de un tipo de valor simplemente mediante una conversión de tipo (ya sea implícita o explícita). El compilador proporciona automáticamente el código fuente adicional que crea el objeto.
Por ejemplo, en versiones de Java anteriores a J2SE 5.0, el siguiente código no se compilaba:
Entero i = new Integer ( 9 ); Entero i = 9 ; // ¡error en versiones anteriores a 5.0!
Los compiladores anteriores a 5.0 no aceptaban la última línea. Integer
son objetos de referencia, que en la superficie no se diferencian de List
, Object
, etc. Para convertir de un int
a un Integer
, uno tenía que instanciar "manualmente" el objeto Integer. A partir de J2SE 5.0, el compilador aceptará la última línea y la transformará automáticamente de modo que se cree un objeto Integer para almacenar el valor 9
. [2] Esto significa que, a partir de J2SE 5.0, algo como , donde y son ellos mismos, se compilará ahora - a y b se desempaquetan, los valores enteros se suman y el resultado se empaqueta automáticamente en un nuevo , que finalmente se almacena dentro de la variable . Los operadores de igualdad no se pueden usar de esta manera, porque los operadores de igualdad ya están definidos para los tipos de referencia, para la igualdad de las referencias; para probar la igualdad del valor en un tipo encajonado, uno todavía debe desempaquetarlos manualmente y comparar los primitivos, o usar el método.Integer c = a + b
a
b
Integer
Integer
c
Objects.equals
Otro ejemplo: J2SE 5.0 permite al programador tratar una colección (como una LinkedList
) como si contuviera int
valores en lugar de Integer
objetos. Esto no contradice lo que se dijo anteriormente: la colección todavía solo contiene referencias a objetos dinámicos y no puede enumerar tipos primitivos. No puede ser una , pero debe ser una en su lugar. Sin embargo, el compilador transforma automáticamente el código para que la lista reciba objetos "silenciosamente", mientras que el código fuente solo menciona valores primitivos. Por ejemplo, el programador ahora puede escribir y pensar como si se agregara a la lista; pero, en realidad, el compilador habrá transformado la línea en .LinkedList<int>
LinkedList<Integer>
list.add(3)
int
3
list.add(new Integer(3))
Con el desempaquetado automático, el compilador suministra automáticamente el código fuente adicional que recupera el valor de ese objeto, ya sea invocando algún método en ese objeto o por otros medios.
Por ejemplo, en versiones de Java anteriores a J2SE 5.0, el siguiente código no se compilaba:
Entero k = new Integer ( 4 ); int l = k . intValue (); // siempre está bien int m = k ; // habría sido un error, pero ahora está bien
C# no admite el desempaquetado automático en el mismo sentido que Java, porque no tiene un conjunto separado de tipos primitivos y tipos de objeto. Todos los tipos que tienen versiones primitivas y de objeto en Java son implementados automáticamente por el compilador de C# como tipos primitivos (valor) o tipos de objeto (referencia).
En ambos lenguajes, el boxeo automático no reduce automáticamente la velocidad, es decir, el siguiente código no se compilará:
DO#:
int i = 42 ; objeto o = i ; // caja int j = o ; // desempaquetar (error) Console . WriteLine ( j ); // línea inalcanzable, el autor podría haber esperado la salida "42"
Java:
int i = 42 ; Objeto o = i ; // caja int j = o ; // desempaquetar (error) System . out . println ( j ); // línea inalcanzable, el autor podría haber esperado la salida "42"
El Object Pascal moderno tiene otra forma de realizar operaciones con tipos simples, similar al boxing, llamados ayudantes de tipo en FreePascal o ayudantes de registro en Delphi y FreePascal en modo Delphi.
Los dialectos mencionados son lenguajes de compilación nativa de Object Pascal y, por lo tanto, carecen de algunas de las características que C# y Java pueden implementar. En particular, la inferencia de tipos en tiempo de ejecución en variables fuertemente tipadas.
Pero la característica está relacionada con el boxing.
Permite al programador usar construcciones como
{ $ifdef fpc}{$mode delphi}{$endif} usa sysutils ; // esta unidad contiene envolturas para los tipos simples var x : entero = 100 ; s : cadena ; begin s := x.ToString ; writeln ( s ) ; end .