Классы-оболочки – это объекты, инкапсулирующие примитивные типы Java.
Каждый примитив Java имеет соответствующую оболочку:
- boolean, byte, short, char, int, long, float, double
- Boolean, Byte, Short, Character, Integer, Long, Float, Double
Все они определены в пакете java.lang, поэтому их не нужно импортировать вручную.
Классы-оболочки
«Какова цель класса-оболочки?» Это один из самых распространенных вопросов на собеседовании по Java.
Generic классы работают только с объектами и не поддерживают примитивы. В результате, если хотим работать с ними, то должны преобразовать примитивные значения в объекты-оболочки.
Например, Java Collection Framework работает исключительно с объектами. Давным-давно (до Java 5, почти 15 лет назад) не было автоупаковки, и нельзя было просто вызвать add(5) для коллекции целых чисел.
В то время эти примитивные значения необходимо было вручную преобразовать в соответствующие классы-оболочки и сохранить в коллекциях.
Сегодня, с автоупаковкой, можно легко сделать ArrayList.add(101), но внутренне Java преобразует примитивное значение в Integer, прежде чем сохранить его в ArrayList, используя метод valueOf().
Преобразование примитивного класса в оболочку
Теперь большой вопрос: как преобразовать примитивное значение в соответствующий класс-оболочку, например, int в Integer или char в Character?
Можно использовать либо конструктор, либо статические фабричные методы для преобразования примитивного значения в объект класса-оболочки.
Однако начиная с Java 9 конструкторы для многих упакованных примитивов, таких как Integer или Long, устарели.
Поэтому настоятельно рекомендуется использовать фабричные методы только для нового кода.
Посмотрим на пример преобразования значения int в объект Integer в Java:
Integer object = new Integer(1);
Integer anotherObject = Integer.valueOf(1);
Метод valueOf() возвращает экземпляр, представляющий указанное значение int.
Он возвращает кэшированные значения, что делает его эффективным. Он всегда кэширует значения от -128 до 127, но также может кэшировать другие значения за пределами этого диапазона.
Точно так же можно преобразовать boolean в Boolean, byte в Byte, char в Character, long в Long, float во Float и double в Double. Если нужно преобразовать String в Integer, нужно использовать метод parseInt(), потому что String не является классом-оболочкой.
С другой стороны, чтобы преобразовать объект-оболочку в примитивное значение, можно использовать соответствующий метод, такой как intValue(), doubleValue() и т. д.:
int val = object.intValue();
Подробную справку можно найти здесь.
Автоупаковка и распаковка
После Java 5 преобразование может выполняться автоматически с помощью функций, называемых автоупаковкой и распаковкой.
Boxing относится к преобразованию примитивного значения в соответствующий объект-оболочку. Поскольку это может происходить автоматически, это называется автобоксингом.
Если объект-оболочка преобразуется в примитивное значение, это называется распаковкой.
На практике это означает, что можно передать примитивное значение методу, который ожидает объект-оболочку, или присвоить примитив переменной, которая ожидает объект:
List<Integer> list = new ArrayList<>();
list.add(1); // автоупаковка
Integer val = 2; // автоупаковка
В этом примере Java автоматически преобразует примитивное значение int в оболочку. Внутри используется метод valueOf() для облегчения преобразования. Например, следующие строки эквивалентны:
Integer value = 3;
Integer value = Integer.valueOf(3);
Хотя это упрощает преобразование и делает код более читаемым, в некоторых случаях не стоит использовать автоупаковку, например, внутри цикла.
Подобно автоупаковке, распаковка выполняется автоматически при передаче объекта методу, который ожидает примитив, или при присвоении его примитивной переменной:
Integer object = new Integer(1);
int val1 = getSquareValue(object); // распаковка
int val2 = object; //распаковка
public static int getSquareValue(int i) {
return i*i;
}
Если напишем метод, который принимает примитивное значение или объект-оболочку, то все равно можем передать им оба значения. Java позаботится о передаче правильного типа, например, примитив или оболочка в зависимости от контекста.
Заключение
В этом кратком руководстве рассказали о классах-оболочках в Java, а также о механизме автоупаковки и распаковки.