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


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

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

8 120

8 ответов:

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

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

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

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

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

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

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

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

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

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

распаковывания является... наоборот:

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

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

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

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

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

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

однако это еще одна вещь, чтобы быть осторожным при работе с коробочной ценности.

интернет .Чистая ФКЗ универсальных коллекций:

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

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

Подробнее см. Главу 16,CLR через C# (2-е издание).

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

распаковка-преобразование ссылочного типа В тип параметра.

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

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

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

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

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

Как и все остальное, автобоксинг может быть проблематичным, если не использовать его тщательно. Классика с исключение 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;
    }
}