Карта / Синтаксис и типы / Примитивы vs обёртки, boxing

Примитивы vs обёртки, boxing

Автобоксинг (autoboxing) — Java сама превращает примитив в обёртку, когда это нужно. Не приходится писать преобразование вручную:

Integer i = 5;            // автобоксинг: int 5 → объект Integer
int x = i;                 // анбоксинг: Integer → обратно в int

Без автобоксинга пришлось бы писать Integer i = Integer.valueOf(5); каждый раз — Java делает это незаметно. Базовое объяснение, чем примитив отличается от обёртки — в теме «Переменные».

Копнуть глубже

Ловушка с кэшем Integer. Java кэширует объекты Integer для чисел от -128 до 127 — это значит, что == для них иногда «случайно» работает, а чуть дальше — ломается:

Integer a = 100;
Integer b = 100;
System.out.println(a == b);   // true — оба из кэша, один и тот же объект

Integer c = 200;
Integer d = 200;
System.out.println(c == d);   // false — за пределами кэша, разные объекты

Вывод: для обёрток всегда сравнивай через .equals(), никогда через == — поведение == зависит от значения числа, и это источник трудноуловимых багов.

NullPointerException при анбоксинге. Если обёртка равна null, а Java пытается её автоматически распаковать в примитив — будет исключение:

Integer count = null;
int x = count;   // 💥 NullPointerException — null нельзя превратить в int
Под капотом

Компилятор подставляет вызовы методов сам — то, что выглядит как простое присваивание, на самом деле скрытый вызов:

Integer i = 5;        // компилятор превращает в: Integer.valueOf(5)
int x = i;             // компилятор превращает в: i.intValue()

Боксинг в коллекциях стоит дорого. List<Integer> не может хранить примитив int напрямую — только объекты. Поэтому каждый add(5) создаёт (или берёт из кэша) объект Integer:

List<Integer> list = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) {
    list.add(i);   // миллион операций боксинга — лишняя нагрузка на GC
}

В горячих циклах с большими объёмами это заметная нагрузка — если важна скорость, используют специализированные структуры под примитивы вместо List<Integer>.

🎤 Закрыл тему, если можешь объяснить:
• что такое автобоксинг и анбоксинг;
• почему `==` для `Integer` иногда true, а иногда false, и откуда берётся NPE при анбоксинге (если дошёл до 2-го слоя).