Секреты кэширования объектов в Java: что скрывает оператор ==?
В процессе прохождения одного тестового задания, связанного с работой с объектами и примитивами, я наткнулась на интересный и неочевидный факт о сравнении объектов в Java. Я дала неверный ответ, и по итогу все началось с того, что я решила проверить, что будет выведено в консоль для следующих строк кода:
Предсказав результат, я была уверена, что вывод будет одинаковым для обеих строк, но к моему удивлению, оказалось, что это не так! Давайте разберёмся, что происходит и почему.
Ответ и его объяснение:
Запустив код, я получила следующий результат:
Первая строка 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 и мы получим то что и будем ожидать:
Спасибо, если прочитали :) Возможно, более опытные уже знают эти особенности, но для меня это стало настоящим открытием, и я была очень рада, что узнала о них.