Классы оболочки в Java
Раньше Вы знакомились с примитивными типами данных (такими, как int, short, boolean и т.д.):

Тем не менее, Вы знаете, что Java — объектно-ориентированный язык программирования . Это значит, что в ней «все, что можно, представлено в виде объектов».
Поэтому, у примитивных типов есть объекты-аналоги — так называемые «классы оболочки» , или «wrapper» (с англ. «обертка, упаковка»):

Класс называется «оболочкой» потому, что он, по сути, копирует то, что уже существует, но добавляет новые возможности для работы с привычными типами .
О названиях
Имена классов нетрудно запомнить — они повторяют имена примитивных типов данных:

Обратите внимание — все классы оболочки пишутся с большой буквы:

Зачем так усложнять
Но зачем они нужны? Если есть обычный int, short, . , зачем нам Short и Integer ? Или, может, оставить только классы оболочки, и не пользоваться примитивами, раз у них функций больше ?

Примитивы и их аналоги, классы оболочки , существуют параллельно, потому что у каждого есть преимущества.
Например, обычный int занимает меньше места, и если нет необходимости проводить над ним особые операции, Ваш компьютер будет работать быстрее.
В свою очередь, с помощью класса-оболочки Integer можно выполнять специальные операции — например, перевести текст в число (с помощью метода .parseInt() для Integer-а ). Если попробовать сделать это с помощью кода самому придется изрядно повозиться.
Integer и int можно сравнить с компьютером и записной книжкой:


Компьютер, безусловно, может больше, чем блокнот — но Вы не будете целый день носить с собой три килограмма для того, чтобы сделать несколько заметок?
Кроме того, есть ситуации, когда нельзя использовать объекты, или наоборот, когда можно использовать только объекты.
Метод .parseInt()
Иногда в объекте типа String содержится число, и Вам нужно с ним работать дальше — умножать, делить, в степень возводить. Но нельзя! Строка же. Что делать?
Урок 5. Классы обертки
Как мы говорили в предыдущем уроке, в Java для каждого примитивного типа существует соответствующий простой объект данных или, как говорится, класс оболочка.
Учитывая примитивный тип (все имена которого начинаются строго с первой строчной буквы), соответствующий объект данных получается, по существу, с заглавной буквы, как показано в следующей таблице:
| Примитивный тип | Класс-оболочка |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
Хотя на первый взгляд может показаться, что есть небольшая разница между примитивным типом и его «обернутым» аналогом (также часто называемым «упакованным в коробку»), между ними существует фундаментальное различие: примитивные типы не являются объектами и у них нет связанного с ними класса, и поэтому они должны обрабатываться иначе, чем другие типы (например, они не могут использоваться в коллекциях, которые будут предметом будущих уроков) и не могут иметь методов.
Чтобы избежать этого различия, Java делает готовые классы доступными для содержания и «оболочки» примитивных типов. Фактически, мы можем думать о классе-оболочке точно так же, как обертка, единственная цель которой — содержать примитивное значение, делая его, с одной стороны, объектом и «украсив» его методами, которые в противном случае не имели бы своего естественного местоположения.
Все классы-оболочки определены в пакете java.lang и квалифицируются как final , поэтому наследовать от них невозможно. Более того, все эти классы неизменяемы, т.е. изменить их значение после построения невозможно.
Хотя Boolean и являются Character производными непосредственно от Object , все объекты данных числового типа являются производными от Number, который, в свою очередь, является прямым потомком Object .

Зачем нужны классы-оболочки в Java?
Разработчиками языка Java было принято очень хорошее решение отделить примитивные типы и классы-оболочки, указав при этом следующее:
- Используйте классы-обертки, когда работаете с коллекциями.
- Используйте примитивные типы для того, чтобы ваши программы были максимально просты.
Еще одним важным моментом является то, что примитивные типы не могут быть null, а классы-оболочки — могут.
От простых типов к объектам данных
Хотя в Java 1.5 введена концепция «автоупаковка и распаковка», которую мы рассмотрим на конкретном уроке, переход от примитивного типа к его обернутой версии в принципе прост, но трудоемок.
Например, обычный int занимает меньше места, и если над ним не планируется проводить особые операции, ваш компьютер будет работать быстрее.
В свою очередь, с помощью класса-оболочки Integer можно выполнять специальные операции — например, перевести текст в число (с помощью метода .parseInt() для Integer-а ). Если попробовать сделать это с помощью кода самому придется изрядно повозиться.
public static void main(String[] args) < int val = 44; //для данного примитивного типа создается класс-оболочка Integer value = new Integer(val); //значение можно "извлечь" из класса-оболочки int valueBack = value.intValue(); >
Специальные методы парсинга
Классы-оболочки — это также место в Java, где очень полезные методы используются для анализа строк и преобразования их в числовые значения, например:
public static void main(String[] args)
Когда мы используем эти методы для преобразования, нам нужно обрабатывать любое генерирование ошибок. На самом деле не все возможные последовательности символов являются числами, возьмем, например, следующий фрагмент:
public static void main(String[] args) < String fortyThree= "fortyThree"; Integer q = new Integer(fortyThree);Парсер не сможет успешно обработать строку, и мы получим ошибку, о которой JVM сообщает с помощью исключения NumberFormatException (подробнее об этом позже).
Строка
Среди типов оболочки мы также можем включить тип String, который имеет много общих характеристик с простыми объектами данных (например, неизменяемость). Но, учитывая важность строк, мы отложим для них целый урок.
Зачем нужны классы обертки в java
В этом руководстве мы рассмотрим плюсы и минусы использования примитивов в Java и соответствующих им классов-оберток.
1. Типы переменных в Java
В языке Java существует два типа переменных: примитивные, например int и boolean, а также ссылочные типы вроде Integer и Boolean (классы-обертки). Для каждого примитивного типа существует, соответствующий ему ссылочный тип.
Классы-обертки являются неизменяемыми: это означает, что после создания объекта его состояние (значение поля value) не может быть изменено; и задекларированы, как final (от этих классов невозможно наследоваться).
Java автоматически производит преобразования между примитивными типами и их обертками:Integer j = 1; // autoboxing int i = new Integer(1); // unboxingПроцесс преобразования примитивных типов в ссылочные называется автоупаковкой (autoboxing), а обратный ему — автораспаковкой (unboxing).
2. Плюсы и минусы
Решение, переменные каких типов использовать, основывается на необходимой нам производительности приложения, объеме доступной памяти и значений по умолчанию с которыми мы собираемся работать.
2.1 Использование памяти единичными объектами
В зависимости от реализации виртуальной машины, эти значения могут изменяться. Например, в виртуальной машине Oracle значения типа boolean сопоставляются со значениями 0 и 1 типа int (это связано с тем, что в VM нет инструкций для работы с булевыми значениями) и, как результат, занимают в памяти 32 бита.
Переменные примитивных типов хранятся в стеке, позволяя иметь к ним быстрый доступ.
Ссылочные переменные ссылаются на объекты, которые хранятся в куче, к ним мы имеем более медленный доступ (рекомендуем ознакомиться с понятиями Стек и Куча, для лучшего усвоения материала). Ссылочные типы имеют определенные накладные расходы относительно их примитивных аналогов.
Накладные расходы зависят от реализации конкретной JVM. Здесь мы приведем результаты для 64-х битной виртуальной машины со следующими параметрами:
В результате, один экземпляр ссылочного типа на данной JVM занимает 128 бит. За исключением Long и Double, которые занимают 192 бита:
- Boolean — 128 бит
- Byte — 128 бит
- Short, Character — 128 бит
- Integer, Float — 128 бит
- Long, Double — 192 бита
Обратите внимание, переменная типа Boolean занимает в 128 раз больше места чем соответствующий ей примитив, тогда как Integer занимает памяти как 4 int переменные.
2.2 Использование памяти массивами
Более интересно обстоят дела с объемом памяти который занимают массивы, рассматриваемых нами типов.
При создании массивов с различным количеством элементов для каждого типа, мы получаем график:
который демонстрирует как массивы различных типов потребляют память (m) в зависимости от количества содержащихся элементов (e):
- long, double: m = 128 + 64e
- short, char: m = 128 + 64(e/4)
- byte, boolean: m) = 128 + 64(e/8)
- the rest: m = 128 + 64(e/2)
где значения в скобках округляются до ближайшего меньшего.
Это может показаться неожиданным, но массивы примитивных типов long и double занимают больше памяти чем их классы-обертки Long и Double соответственно.

2.3 Производительность
Производительность Java кода, довольно тонкий вопрос, сильно зависящий от аппаратной части устройства на котором он исполняется, от различных оптимизационных процессов, выполняемых компилятором, от конкретной JVM, а также от других процессов, происходящих в операционной системе.
Мы уже упоминали ранее, что переменные примитивных типов живут в стеке, тогда как ссылочные переменные хранят ссылки на объекты расположенные в куче. Это важное свойство, определяющее скорость доступа к данным.
Чтобы продемонстрировать насколько операции над примитивными типами быстрее чем над их классами-обертками, создадим массив из миллиона элементов в котором все элементы одинаковы, кроме последнего. Затем мы попытаемся найти этот элемент и сравним результаты производительности работы массива переменных примитивных типов с массивом ссылочных переменных.
Мы используем известный инструмент тестирования производительности JMH, а результаты операции суммируем в диаграмме:
Как мы видим, даже выполнение такой простой операции требует значительно больше времени для классов-оберток, чем для их примитивных аналогов.
В случае более трудоемких операций, таких как сложение, умножение или деление разница в скорости может значительно увеличиться.
Классы оболочки
Очень часто необходимо создать класс, основное назначение которого содержать в себе какое-то примитивное значение. Например, как мы увидим в следующих занятиях, обобщенные классы и в частности коллекции работают только с объектами. Поэтому, чтобы каждый разработчик не изобретал велосипед, в Java SE уже добавлены такие классы, которые называются оболочки типов (или классы обертки, Wrappers).
К оболочкам типов относятся классы Double , Float , Long , Integer , Short , Byte , Character , Boolean , Void . Для каждого примитивного значения и ключевого слова void есть свой класс двойник. Имя класса, как вы видите, совпадает с именем примитивного значения. Исключения составляют класс Integer (примитивный тип int ) и класс Character (примитивный тип char ). Кроме содержания в себе значения, классы оболочки предоставляют обширный ряд методов, которые мы рассмотрим в этом уроке.
Объекты классов оболочек неизменяемые (immutable). Это значит, что объект не может быть изменен.
Все классы обертки числовых типов имеют переопределенный метод equals(Object) , сравнивающий примитивные значения объектов.
2. Конструкторы оболочек
В следующей таблицы для каждого класса оболочки указан соответствующий примитивный тип и варианты конструкторов. Как вы видите каждый класс имеет два конструктора: один на вход принимает значение соответствующего примитивного значения, а второй - значение типа String. Исключения: класс Character , у которого только один конструктор с аргументом char и класс Float , объявляющий три конструктора - для значения float , String и еще double .
Примитивный тип
Оболочка
Аргументы конструктора
