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

StackOverflow https://stackoverflow.com/questions/13055

Вопрос

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

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

Это было полезно?

Решение

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

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

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

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

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

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

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

Другие советы

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

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

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

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

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

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

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

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

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

В .Net:

Часто вы не можете полагаться на тип переменной, которую будет использовать функция, поэтому вам нужно использовать объектную переменную, которая простирается от наименьшего общего знаменателя - in .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

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

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

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

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

Дополнительные сведения см. в главе 16, Среда CLR через C# (2-е издание).

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

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

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

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

Упаковка и распаковка облегчает обработку типов значений как объектов.Упаковка означает преобразование значения в экземпляр ссылочного типа объекта.Например, Int является классом и int это тип данных.Преобразование int Для Int является примером бокса, в то время как преобразование Int Для 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;
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top