Что такое бокс и распаковка и какие компромиссы?

Я ищу четкий, краткий и точный ответ.

В идеале, как фактический ответ, хотя приветствуются ссылки на хорошие объяснения.

Ответ 1

Вставные значения структуры данных, которые являются минимальными обертками вокруг примитивных типов *. Вставные значения обычно сохраняются как указатели на объекты на куче.

Таким образом, вложенные в квадрат значения используют больше памяти и берут минимум два поиска памяти для доступа: один раз, чтобы получить указатель, а другой - указатель на примитив. Очевидно, это не то, что вы хотите в своих внутренних циклах. С другой стороны, значения в коробке обычно лучше работают с другими типами в системе. Поскольку они являются первоклассными структурами данных на языке, они имеют ожидаемые метаданные и структуру, которые имеют другие структуры данных.

В сборниках Java и Haskell обобщенные коллекции не могут содержать unboxed values. Общие коллекции в .NET могут содержать unboxed значения без штрафов. Где Java-дженерики используются только для проверки типа компиляции,.NET будет генерировать определенные классы для каждого генерируемого типа, созданного при запуске.

Java и Haskell имеют распакованные массивы, но они явно менее удобны, чем другие коллекции. Однако, когда требуется максимальная производительность, стоит немного неудобства, чтобы избежать накладных расходов на бокс и распаковку.

* Для этого обсуждения примитивным значением является любое, которое может быть сохранено в стеке вызовов, а не храниться как указатель на значение на куче. Часто это всего лишь типы машин (ints, floats и т.д.), Структуры, а иногда и массивы статического размера..NET-land называет их типами значений (в отличие от ссылочных типов). Java-люди называют их примитивными типами. Haskellions просто называют их незанятыми.

** Я также сосредоточен на Java, Haskell и С# в этом ответе, потому что это то, что я знаю. Для того, что стоит, Python, Ruby и Javascript имеют исключительно значения в коробке. Это также называется подходом "Все является объектом" ***.

*** Предостережение. Достаточно продвинутый компилятор /JIT может в некоторых случаях фактически обнаруживать, что значение, которое семантически боксировано при просмотре источника, может безопасно быть unboxed значением во время выполнения. По сути, благодаря блестящим языковым реализаторам ваши коробки иногда бесплатны.

Ответ 2

из С# 3.0 В двух словах:

Бокс - это акт приведения ценности введите тип ссылки:

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

unboxing - это... обратное:

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

Ответ 3

Бокс и распаковка - это процесс преобразования примитивного значения в объект-ориентированный класс-оболочка (бокс) или преобразование значения из класса, ориентированного на объект, обратно в примитивное значение (unboxing).

Например, в java вам может потребоваться преобразовать значение int в Integer (бокс), если вы хотите сохранить его в Collection, поскольку примитивы не могут быть сохранены в Collection, только объекты. Но когда вы захотите вернуть его из Collection, вы можете получить значение как int, а не Integer, чтобы его можно было распаковать.

Бокс и распаковка не являются изначально плохими, но это компромисс. В зависимости от реализации языка он может быть медленнее и интенсивнее, чем просто использовать примитивы. Однако он также может позволить вам использовать структуры данных более высокого уровня и добиться большей гибкости в вашем коде.

В наши дни это чаще всего обсуждается в контексте функции "autoboxing/autounboxing" Java (и другого языка). Вот java-ориентированное объяснение автобоксинга.

Ответ 4

В .Net:

Часто вы не можете полагаться на то, какой тип переменной будет потреблять, поэтому вам нужно использовать переменную объекта, которая простирается от самого низкого общего знаменателя - в .Net это object.

Однако object - это класс и сохраняет его содержимое в качестве ссылки.

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

В то время как обе они содержат одну и ту же информацию, второй список больше и медленнее. Каждое значение во втором списке фактически является ссылкой на object, который содержит int.

Это называется boxed, потому что int заверяется object. Когда его отбрасывание int распаковывается - преобразуется обратно к нему.

Для типов значений (т.е. все structs) это медленно и потенциально использует намного больше места.

Для ссылочных типов (т.е. все classes) это гораздо менее проблематично, поскольку они все равно сохраняются как ссылка.

Еще одна проблема с типом бокс-значения заключается в том, что не очевидно, что вы имеете дело с полем, а не по значению. Когда вы сравниваете два structs, тогда вы сравниваете значения, но когда вы сравниваете два classes, а затем (по умолчанию) вы сравниваете ссылку - т.е. Являются ли они одним и тем же экземпляром?

Это может сбивать с толку при работе со значениями типов в штучной упаковке:

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

Легко работать:

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

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

Однако при работе со значениями в штучной упаковке следует соблюдать осторожность.

Ответ 5

Общие коллекции .NET FCL:

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

были разработаны для решения проблем производительности бокса и распаковки в предыдущих реализациях коллекции.

Подробнее см. главу 16, CLR через С# (второе издание).

Ответ 6

Бокс - это процесс преобразования типа значения в ссылочный тип.

Unboxing - это преобразование ссылочного типа в тип значения.

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

Тип значения:
int, char и структуры, перечисления. Тип ссылки: Классы, интерфейсы, массивы, строки и объекты

Ответ 7

Бокс и распаковка облегчают использование типов значений для обработки объектов. Бокс означает преобразование значения в экземпляр ссылочного типа объекта. Например, Int - это класс, а Int - тип данных. Преобразование Int в Int является примером бокса, тогда как преобразование Int в Int является распаковкой. С другой стороны, концепция помогает в сборе мусора, Unboxing, преобразует тип объекта в тип значения.

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

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

Ответ 8

Как и все остальное, автобоксинг может быть проблематичным, если его не использовать осторожно. Классика состоит в том, чтобы в конечном итоге получить исключение NullPointerException и не сможет отслеживать его. Даже с отладчиком. Попробуйте следующее:

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;
    }
}