Секреты кэширования объектов в Java: что скрывает оператор ==?

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

//Что будет выведено в консоль? Integer a = 1; Integer b = 1; Integer c = 325; Integer d = 325; System.out.println(a == b); System.out.println(c == d);

Предсказав результат, я была уверена, что вывод будет одинаковым для обеих строк, но к моему удивлению, оказалось, что это не так! Давайте разберёмся, что происходит и почему.

Ответ и его объяснение:

Запустив код, я получила следующий результат:

true false

Первая строка System.out.println(a == b); вывела true, что вполне ожидаемо, если считать, что обе переменные ссылаются на один и тот же объект с числом 1. Однако вторая строка System.out.println(c == d); неожиданно вернула false, несмотря на то, что обе переменные, казалось бы, тоже содержат одно и то же значение – 325. В чем же дело?

Магия кэширования

Чтобы понять, почему это произошло, нужно углубиться во внутреннюю работу Java. Оператор "==" при сравнении объектов в Java проверяет, ссылаются ли обе переменные на один и тот же объект в памяти. В случае с Integer, Boolean, Character, и Long, чтобы улучшить производительность, Java применяет кэширование значений для некоторых диапазонов чисел.
Для Integer JVM кэширует значения в диапазоне от -128 до 127. Это означает, что при создании объекта Integer в этом диапазоне Java не создаёт новый объект, а использует уже существующий из пула кэшированных значений.

Почему a == b вернул true.
Когда мы присваиваем 1 переменным a и b, Java использует одно и то же значение из пула кэшированных объектов Integer. Поэтому обе переменные a и b ссылаются на один и тот же объект, и a == b возвращает true.

Почему c == d вернул false. Значение 325 находится за пределами кэшируемого диапазона, и каждый раз при присвоении такого значения создаётся новый объект Integer. Поэтому c и d ссылаются на разные объекты, даже если у них одинаковое значение, и результат c==d будет false.

Вывод.
С подобной ситуацией мы сталкиваемся при попытке сравнить два объекта String и знаем, что надо делать, чтобы сравнить значения, а не ссылки на объекты. В общем, чтобы избежать путаницы стоит использовать equals.
Попробуем использовать equals и мы получим то что и будем ожидать:

true true

Спасибо, если прочитали :) Возможно, более опытные уже знают эти особенности, но для меня это стало настоящим открытием, и я была очень рада, что узнала о них.

11
Начать дискуссию