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

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

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

16.08.2008 08:34:25
Это действительно не зависит от языка?
Henk Holterman 29.10.2012 12:51:04
@HenkHolterman это определенно не зависит от языка, хотя это также не относится ко всем языкам - например, это различие не будет иметь значения для большинства языков с динамической типизацией. Я не уверен, какой тег можно использовать вместо - language-but-not-type-agnostic? static-language-agnostic? Я не уверен, что ТАК нужно различие; может быть, хороший вопрос для мета, хотя.
Keith 29.10.2012 13:08:21
8 ОТВЕТОВ
РЕШЕНИЕ

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

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

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

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

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

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

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

185
12.12.2012 05:49:18
Почему, хотя в штучной упаковке, какое преимущество дает CLR или что-то еще, получающее значения формы бокса?
PositiveGuy 26.10.2010 01:13:46
Короче говоря (ха-ха), это просто еще один объект, который очень удобен. Примитивы (по крайней мере в Java) не происходят от Object, не могут иметь полей, не могут иметь методов и просто ведут себя совершенно иначе, чем другие типы значений. С другой стороны, работа с ними может быть очень быстрой и экономичной. Таким образом, компромисс.
Peter Burns 24.11.2010 19:22:57
Javascript имеет так называемые типизированные массивы (новый UInt32Array и т. Д.), Которые представляют собой массивы распакованных целочисленных значений и чисел с плавающей точкой.
nponeccop 30.06.2012 06:03:18

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

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

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

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

71
16.08.2008 08:53:26

В .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.

Это называется в штучной упаковке, потому что 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's equals

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

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

23
3.10.2012 08:14:26
В vb.net различие между семантикой равенства более четкое, Objectне реализует оператор равенства, но типы классов можно сравнивать с Isоператором; и наоборот, Int32может использоваться с оператором равенства, но не Is. Это различие делает намного более ясным, какой тип сравнения делается.
supercat 7.12.2012 23:52:01

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

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

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

распаковка это ... обратное

// unboxing o
object o = 9; 
int x = (int)o; 
125
2.01.2014 06:59:14

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

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

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

Для получения дополнительной информации см. Главу 16, CLR через C # (2-е издание) .

3
16.08.2008 18:57:07

Как и все остальное, автобокс может быть проблематичным, если не использовать осторожно. Классика заключается в том, чтобы получить исключение 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;
    }
}
-2
19.09.2008 13:04:56
Это просто плохой код, и он не имеет ничего общего с автобоксом. Переменная iинициализируется преждевременно. Либо сделайте его пустым объявлением ( Integer i;), чтобы компилятор мог указать, что вы забыли его инициализировать, либо дождитесь его объявления, пока не узнаете его значение.
erickson 24.09.2008 23:14:25
Хм, и если я сделаю что-то промежуточное внутри блока try catch, то компилятор заставит меня что-то инициализировать. Это не настоящий код - это пример того, как это может произойти.
PEELY 26.09.2008 14:24:24
Что это демонстрирует? Нет абсолютно никаких причин использовать объект Integer. Вместо этого вам теперь приходится иметь дело с потенциальным NullPointer.
Richard Clayton 29.06.2010 01:12:37

Boxingэто процесс преобразования типа значения в ссылочный тип. Принимая во внимание Unboxing, что преобразование ссылочного типа в тип значения.

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

Типы значений являются: int, charи structures, enumerations. Ссылочные типы являются: Classes, interfaces, arrays, stringsиobjects

4
20.01.2020 22:57:42

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

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

o=123;
i=(int)o; //Unboxing.
1
21.06.2016 12:02:54
В JavaScript var ii = 123; typeof ii возвращается number. var iiObj = new Number(123); typeof iiObjвозвращается object. typeof ii + iiObjвозвращается number. Так что это javascript-эквивалент бокса. Значение iiObj было автоматически преобразовано в примитивное число (без коробки), чтобы выполнить арифметику и вернуть значение без коробки.
PatS 18.11.2018 22:46:56