— это автоматическое преобразование Java между (, ) и их (, ). Это удобно, но имеет тонкие недостатки — оверхед производительности, неожиданное поведение и риск .
intdoubleIntegerDouble==NullPointerExceptionInteger boxed = 42; // autoboxing: int → Integer (Integer.valueOf(42))
int unboxed = boxed; // auto-unboxing: Integer → int (boxed.intValue())
List<Integer> nums = new ArrayList<>();
nums.add(5); // autoboxes int 5 → Integer (collections need objects)
int x = nums.get(0); // auto-unboxes Integer → int
Это происходит автоматически, потому что коллекции и обобщённые типы требуют объектов (вы не можете иметь List<int>), поэтому Java прозрачно упаковывает примитивы.
Integer a = 1000;
Integer b = 1000;
a == b; // ❌ FALSE — different Integer OBJECTS (reference comparison)
a.equals(b); // ✅ true — value comparison
// the WORSE trap — the Integer cache makes small values seem to work:
Integer c = 100, d = 100;
c == d; // TRUE — Java CACHES Integers from -128 to 127 (same object)
Integer e = 200, f = 200;
e == f; // FALSE — outside the cache range → different objects
Это коварно: == на Integer работает для небольших значений (кэшировано), но не работает для больших — код, который кажется правильным при тестировании, ломается в production. Всегда используйте .equals() для сравнения значений обёрток или сначала распакуйте примитивы.
Integer value = null; // a wrapper can be null
int x = value; // 💥 NullPointerException — unboxing null calls null.intValue()
Map<String, Integer> map = new HashMap<>();
int count = map.get("missing"); // 💥 NPE — get() returns null, then unboxing fails
Распаковка null-обёртки выбрасывает NPE — частый, неожиданный сбой, особенно при поиске в картах, возвращающих null.
// ❌ autoboxing in a hot loop — creates millions of Integer objects (GC pressure, slow)
Long sum = 0L; // WRONG type — wrapper
for (long i = 0; i < 1_000_000; i++) {
sum += i; // unbox, add, re-box → new Long each iteration!
}
// ✅ use primitives in hot paths
long sum = 0L; // primitive — no boxing
Повторяющаяся упаковка/распаковка создаёт избыточные объекты, что снижает производительность в плотных циклах.
Автоупаковка удобна и повсеместна (коллекции, обобщённые типы полагаются на неё), но её недостатки вызывают реальные, сложно диагностируемые баги.
Ловушка == особенно опасна: сравнение Integerов с помощью == работает для кэшированных небольших значений (-128 до 127), но молча не работает для больших — баг, который проходит тесты и ломается в production — что делает .equals() (или распаковку) необходимыми для сравнения обёрток. NullPointerException от распаковки null-обёрток (распространено при поиске в картах) — ещё один частый сбой.
А упаковка в горячих циклах создаёт ненужные объекты, снижая производительность.
Понимание того, когда происходит упаковка, проблемы сравнения значения и ссылки, риск null-распаковки и использование примитивов в критичном по производительности коде важно для написания корректного и эффективного Java — а поведение Integer-кэша с == — это классический вопрос интервью, который раскрывает глубокое понимание.