Страницы

Поиск по вопросам

четверг, 12 декабря 2019 г.

Что такое упаковка и распаковка(boxing/unboxing)?

#java #java_faq


Что это вообще такое упаковка и распаковка (boxing/unboxing) и зачем она нужна?

Был бы рад примерам.
    


Ответы

Ответ 1



Работа с объектами неизбежно влечет за собой накладные расходы по памяти и быстродействию. Чтобы избежать этого, используются переменные примитивных типов. Это, по сути, простые переменные, как в C или С++. byte занимает 1 байт памяти, int и float - по 4 байта, long и double - по 8 байт и т.д. В отличие от операций с объектами, операции с переменными примитивных типов не требуют выделения/освобождения памяти и выполняются быстро - они в в большинстве случаев в конечном счете компилируются в простые процессорные инструкции, что позволяет программам на Java часто работать со скоростью, сравнимой с программами, написанными на простых компилируемых (непосредственно в машинный код) языках (типа тех же C, С++). Неудобство с ними в том, что с ними нельзя делать то, что можно делать со всеми объектами - они не имеют методов. Нельзя, например написать int a = 5; ArrayList list = new ArrayList(); String s = a.toString(); // Ошибка list.add(a)) // Можно, но произойдет автоупаковка // и в коллекцию будет помещен Integer их нельзя помещать в коллекции и прочее. Для того, чтобы обойти это неудобство, для всех примитивных типов существуют соответствующие классы-оболочки, объекты которых могут хранить значения примитивных типов, но обладает всеми свойствами нормальных объектов: Integer a = 5; ArrayList list = new ArrayList(); String s = a.toString(); // OK list.add(a)) // OK Создание объекта-оболочки из переменной примитивного типа называется упаковкой (boxing), а получение значения примитивного типа из объекта-оболочки -- распаковкой (unboxing). Объектам-оболочкам можно присваивать значения примитивных типов, а переменным примитивных типов - значения переменных-оболочек, при этом при необходимости автоматически создаются объекты-оболочки с соответствующими значениями (автоупаковка) или наоборот, примитивные значения извлекаются из оболочек (автораспаковка): int a = 5; Integer b = 10; a = b; // OK, атораспаковка b = a * 123; // OK, автоупаковка В тех случаях, когда по контексту требуются объекты (присваивание, вызов метода с передачей параметров), а мы используем значения примитивных типов (переменные или выражения типа 2 * 3), всегда происходит автоупаковка. Все объекты-оболочки - неизменяемые (immutable) типы, т.е. когда мы присваиваем им новое значение, фактически на замену прежнему объекту создается новый.

Ответ 2



В версиях ниже JDK 1.5 было не легко преобразовывать примитивные типы данных, такие как int, char, float, double в их классы оболочки Integer, Character, Float, Double. Начиная с версии JDK 5 эта функция, преобразования примитивных типов в эквивалентные объекты, реализована автоматически. Это свойство известно как Автоупаковка(Autoboxing). Обратный процесс соответственно – Распаковка(Unboxing) т.е. процесс преобразования объектов в соответствующие им примитивные типы. Пример кода для автоупаковки и распаковки представлен ниже: Автоупаковка 1 Integer integer = 9; Распаковка 1 int in = 0; 2 in = new Integer(9); Когда используется автоупаковка и распаковка? Автоупаковка применяется компилятором Java в следующих условиях: Когда значение примитивного типа передается в метод в качестве параметра метода, который ожидает объект соответствующего класса-оболочки. Когда значение примитивного типа присваивается переменной, соответствующего класса оболочки. Cсылка на источник

Ответ 3



Для понимания смысла упаковки-распаковки нужно понимать, как работает исполняемая среда и ваша программа на уровне процессора, а так же понимать, что термин ООП это всего лишь надстройка над классическим структурным программированием. Промежуточный байт-код во время выполнения программы преобразуется исполняемой средой в команды конкретного микропроцессора. Есть 3 основных способа хранения, обработки данных и их взаимодействия с программой: процессор-регистр, процессор-стек, и процессор-память. Команды работы с регистрами самые короткие и быстрые, со стеком - короткие, но выполняются на большее число тактов процессора, а команды работы с памятью - самые длинные и медленные. При этом в большинстве случаев простые типы данных хранятся и обрабатываются в регистрах процессора и в стеке, классы и более сложные типы данных хранятся в так называемой "куче" - динамической памяти, которая контролируется исполняемой средой. Механизм кучи достаточно сложен и работа с кучей по времени всегда дольше. Связка стек-регистры максимально эффективна при циклических алгоритмах, где в каждой итерации имеются длинные сложные вычисления, при этом циклический фрагмент кода с регистровой адресацией выполняется в сотни, а то и в десятки тысяч раз быстрее, чем если бы данные хранились в куче:) зато хранение данных в памяти упрощает программу и уменьшает ее размер, а также позволяет использовать все прелести ООП. Упаковку-распаковку придумали для того, чтобы избежать потери производительности программного обеспечения - если критически важна скорость - распаковываем свои данные в простой компактный формат, если скорость не критична - упаковываем в объектный тип и упрощаем программу. Кроме скорости возможна ситуация со значительными затратами ресурсов - к примеру, вам необходимо создать массив из миллиона однобайтовых элементов: что лучше использовать - примитивный однобайтовый тип или упакованный размером в несколько десятков байт?

Комментариев нет:

Отправить комментарий