logo
Методичка Java

3.6. Оболочечные классы. Упаковка (boxing) и распаковка (unboxing)

В ряде случаев вместо значения примитивного типа требуется объект. Например, для работы со списками объектов. Это связано с тем, что работа с объектами в Java может быть унифицирована, поскольку все классы Java являются наследниками класса Object, а для примитивных типов этого сделать нельзя.

Для таких целей в Java каждому примитивному типу сопоставляется объектный тип, то есть класс. Такие классы называются оболочечными (class wrappers). В общем случае они имеют те же имена, что и примитивные типы, но начинающиеся не со строчной, а с заглавной буквы. Исключение почему-то составляют типы int и char, для которых имена оболочечных классов Integer и Character.

Примитивный тип

Оболочечный класс

byte

Byte

short

Short

char

Character

int

Integer

long

Long

float

Float

double

Double

Внимание! Класс Character несколько отличается от остальных оболочечных числовых классов потому, что тип char “не вполне числовой”.

Основное назначение оболочечных классов – создание объектов, являющихся оболочками над значениями примитивных типов. Процесс создание такого объекта (“коробки” - box) из значения примитивного типа называется упаковкой (boxing), а обратное преобразование из объекта в величину примитивного типа – распаковкой (unboxing). Оболочечные объекты (“обёртки” для значения примитивного типа) хранят это значение в поле соответствующего примитивного типа, доступном по чтению с помощью функции имяТипаValue(). Например, метода byteValue() для объекта типа Byte. Но во многих случаях можно вообще не обращать внимания на отличие переменных с типом оболочечных классов от переменных примитивных типов, так как упаковка и распаковка при подстановке такого объекта в выражение происходит автоматически, и объект оболочечного типа в этих случаях внешне ведёт себя как число. Таким образом, если нам необходимо хранить в объекте числовое значение, следует создать объект соответствующего оболочечного типа.

Например, возможны такие фрагменты кода:

Integer obj1=10;

int i1= obj1*2;

Byte b=1;

obj1=i1/10;

b=2;

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

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

Byte.MIN_VALUE, Byte.MAX_VALUE, Float.MIN_VALUE, Float.MAX_VALUE, Double.MIN_VALUE, Double.MAX_VALUE и т.п.

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

Byte.parseByte(строка)

Short.parseShort(строка)

Integer.parseInt(строка)

Long.parseLong(строка)

Float.parseFloat(строка)

Double.parseDouble(строка)

Они преобразуют строку в число соответствующего типа.

Вызовы

Byte.valueOf(строка)

Short.valueOf(строка)

Integer.valueOf(строка)

Long.valueOf (строка)

Float.valueOf (строка)

Double.valueOf (строка)

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

Примеры использования оболочечных классов:

int n1=Integer.MAX_VALUE;

double d1= Double.MIN_VALUE;

Отметим, что присваивание

double d2= Double.parseDouble(jTextField1.getText());

будет работать совершенно так же, как

double d2= Double.valueOf(jTextField1.getText());

несмотря на то, что во втором случае методом valueOf создаётся объект оболочечного типа Double. Поскольку в левой части присваивания стоит переменная типа double, происходит автоматическая распаковка, и переменной d2 присваивается распакованное значение. Сам объект при этом становится мусором – программная связь с ним теряется, и он через некоторое время удаляется из памяти системой сборки мусора. В данном случае ни быстродействие, ни объём памяти некритичны, поскольку операции взаимодействия с пользователем по компьютерным меркам очень медленные, а один объект оболочечного типа занимает пренебрежимо мало места в памяти (около сотни байт). Так что с потерями ресурсов в этом случае можно не считаться, обращая внимание только на читаемость текста программы. Поэтому автор предпочитает второй вариант присваивания: хотя он и “неоптимальный” по затрате ресурсов, но более читаем.