Pregunta

Busco una respuesta clara, concisa y precisa.

Idealmente como la respuesta real, aunque se aceptan enlaces a buenas explicaciones.

¿Fue útil?

Solución

Los valores en caja son estructuras de datos que son envoltorios mínimos alrededor tipos primitivos*.Los valores encuadrados normalmente se almacenan como punteros a objetos en el montón.

Por lo tanto, los valores encuadrados utilizan más memoria y requieren como mínimo dos búsquedas de memoria para acceder:una vez para obtener el puntero y otra para seguir ese puntero hasta la primitiva.Obviamente este no es el tipo de cosas que deseas en tus bucles internos.Por otro lado, los valores encuadrados suelen funcionar mejor con otros tipos del sistema.Dado que son estructuras de datos de primera clase en el lenguaje, tienen los metadatos y la estructura esperados que tienen otras estructuras de datos.

En Java y Haskell, las colecciones genéricas no pueden contener valores sin caja.Las colecciones genéricas en .NET pueden contener valores sin caja sin penalizaciones.Cuando los genéricos de Java solo se usan para la verificación de tipos en tiempo de compilación, .NET generar clases específicas para cada tipo genérico instanciado en tiempo de ejecución.

Java y Haskell tienen matrices sin caja, pero son claramente menos convenientes que las otras colecciones.Sin embargo, cuando se necesita un rendimiento máximo, vale la pena un pequeño inconveniente para evitar los gastos generales de empaquetar y desempaquetar.

* Para esta discusión, un valor primitivo es cualquiera que pueda almacenarse en la pila de llamadas, en lugar de almacenarse como un puntero a un valor en el montón.Con frecuencia, son solo los tipos de máquina (ints, flotantes, etc.), estructuras y, a veces, matrices de tamaño estático..NET-land los llama tipos de valor (a diferencia de tipos de referencia).La gente de Java los llama tipos primitivos.Haskellions simplemente los llama sin caja.

** También me estoy centrando en Java, Haskell y C# en esta respuesta, porque eso es lo que sé.Por si sirve de algo, Python, Ruby y Javascript tienen valores exclusivamente encuadrados.Esto también se conoce como el enfoque "Todo es un objeto"***.

*** Advertencia:Un compilador/JIT suficientemente avanzado puede, en algunos casos, detectar que un valor que está semánticamente encuadrado cuando se mira la fuente, puede ser con seguridad un valor sin encuadrar en tiempo de ejecución.En esencia, gracias a los brillantes implementadores del lenguaje, tus cajas a veces son gratuitas.

Otros consejos

de C# 3.0 en pocas palabras:

El boxeo es el acto de lanzar un tipo de valor en un tipo de referencia:

int x = 9; 
object o = x; // boxing the int

el desempaquetado es...el revés:

// unboxing o
object o = 9; 
int x = (int)o; 

Boxing & unboxing es el proceso de convertir un valor primitivo en una clase contenedora orientada a objetos (boxing), o convertir un valor de una clase contenedora orientada a objetos nuevamente al valor primitivo (unboxing).

Por ejemplo, en Java, es posible que necesites convertir un int valor en un Integer (boxeo) si desea guardarlo en un Collection porque las primitivas no se pueden almacenar en un Collection, solo objetos.Pero cuando quieras volver a sacarlo del Collection es posible que desee obtener el valor como un int y no un Integer entonces lo desempaquetarías.

Boxear y unboxing no es inherentemente malo, pero es una compensación.Dependiendo de la implementación del lenguaje, puede ser más lento y consumir más memoria que simplemente usar primitivos.Sin embargo, también puede permitirle utilizar estructuras de datos de nivel superior y lograr una mayor flexibilidad en su código.

Hoy en día, se discute más comúnmente en el contexto de la función "autoboxing/autounboxing" de Java (y otros lenguajes).Aquí hay un explicación centrada en java de autoboxing.

En la red:

A menudo no se puede confiar en el tipo de variable que consumirá una función, por lo que es necesario utilizar una variable de objeto que se extienda desde el mínimo común denominador; en .Net esto es object.

Sin embargo object es una clase y almacena su contenido como referencia.

List<int> notBoxed = new List<int> { 1, 2, 3 };
int i = notBoxed[1]; // this is the actual value

List<object> boxed = new List<object> { 1, 2, 3 };
int j = (int) boxed[1]; // this is an object that can be 'unboxed' to an int

Si bien ambos contienen la misma información, la segunda lista es más grande y más lenta.Cada valor en la segunda lista es en realidad una referencia a un object que sostiene el int.

Esto se llama encuadrado porque el int está envuelto por el object.Cuando se echa hacia atrás el int no está en caja, se vuelve a convertir a su valor.

Para tipos de valor (es decir,todo structs) esto es lento y potencialmente utiliza mucho más espacio.

Para tipos de referencia (es decir,todo classes) esto es un problema mucho menor, ya que de todos modos se almacenan como referencia.

Otro problema con un tipo de valor en cuadro es que no es obvio que se trata del cuadro, en lugar del valor.Cuando comparas dos structs entonces estás comparando valores, pero cuando comparas dos classes entonces (de forma predeterminada) estás comparando la referencia, es decir¿Son estos el mismo caso?

Esto puede resultar confuso cuando se trata de tipos de valores en cuadros:

int a = 7;
int b = 7;

if(a == b) // Evaluates to true, because a and b have the same value

object c = (object) 7;
object d = (object) 7;

if(c == d) // Evaluates to false, because c and d are different instances

Es fácil solucionarlo:

if(c.Equals(d)) // Evaluates to true because it calls the underlying int's equals

if(((int) c) == ((int) d)) // Evaluates to true once the values are cast

Sin embargo, hay otra cosa con la que hay que tener cuidado cuando se trata de valores en cajas.

Las colecciones genéricas de .NET FCL:

List<T>
Dictionary<TKey, UValue>
SortedDictionary<TKey, UValue>
Stack<T>
Queue<T>
LinkedList<T>

Todos fueron diseñados para superar los problemas de rendimiento de boxing y unboxing en implementaciones de colecciones anteriores.

Para obtener más información, consulte el capítulo 16, CLR a través de C# (segunda edición).

El boxeo es el proceso de conversión de un tipo de valor en un tipo de referencia.

Unboxing es la conversión de un tipo de referencia en un tipo de valor.

EX: int i=123;
    object o=i;// Boxing
    int j=(int)o;// UnBoxing

Los tipos de valor son:
int, char y estructuras, enumeraciones.Los tipos de referencia son:Clases, interfaces, matrices, cadenas y objetos.

Boxing y unboxing facilitan que los tipos de valores sean tratados como objetos.Boxear significa convertir un valor en una instancia del tipo de referencia de objeto.Por ejemplo, Int es una clase y int es un tipo de datos.Mudado int a Int es un ejemplo del boxeo, mientras que convertir Int a int está desempaquetando.El concepto ayuda en la recolección de basura. Unboxing, por otro lado, convierte el tipo de objeto en tipo de valor.

int i=123;
object o=(object)i; //Boxing

o=123;
i=(int)o; //Unboxing.

Como cualquier otra cosa, el autoboxing puede resultar problemático si no se utiliza con cuidado.Lo clásico es terminar con una NullPointerException y no poder rastrearla.Incluso con un depurador.Prueba esto:

public class TestAutoboxNPE
{
    public static void main(String[] args)
    {
        Integer i = null;

        // .. do some other stuff and forget to initialise i

        i = addOne(i);           // Whoa! NPE!
    }

    public static int addOne(int i)
    {
        return i + 1;
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top