От числа к объекту

В Java `int` — это простое числовое значение, а `Integer` — объект-обёртка, который хранит такое значение. Когда число нужно использовать там, где требуется объект, Java может автоматически упаковать его: например, присваивание `Integer n = 42` превращает `42` в объект `Integer`.

Создавать отдельный объект для каждого часто встречающегося небольшого числа было бы лишней работой. Поэтому стандартное преобразование через `Integer.valueOf` использует кэш: для значений от −128 до 127 оно возвращает заранее подготовленные объекты. Повторное обращение к одному из этих чисел может получить ту же ссылку, а не новый объект.

Почему важна граница

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

Отсюда возникает ловушка: оператор `==` у объектов сравнивает не числовое содержимое, а то, указывают ли две переменные на один и тот же объект. Поэтому два `Integer` со значением `127` могут пройти сравнение `==`, а два объекта со значением `128` — нет, хотя числа внутри равны. Для сравнения значений используют `equals` или преобразуют объекты в простые числа.

Кэш — небольшая оптимизация, но он наглядно показывает, почему одинаковые на вид числа и одинаковые объекты в Java не всегда одно и то же.