TL; DR
Java кэширует упакованные экземпляры Integer из -128
в 127
. Поскольку вы используете ==
для сравнения ссылки на объекты вместо значений , будут соответствовать только кешированные объекты. Либо работайте с long
неупакованными примитивными значениями, либо используйте .equals()
для сравнения ваших Long
объектов.
Длинная (каламбурная) версия
Почему возникает проблема при сравнении переменной Long со значением больше 127? Если тип данных указанной выше переменной является примитивным (длинным), тогда код работает для всех значений.
Java кэширует экземпляры целочисленных объектов в диапазоне от -128 до 127 . При этом сказано:
- Если вы установите значение N Long для переменных
127
( кэшировано ), то все ссылки будут указывать на один и тот же экземпляр объекта. (N переменных, 1 экземпляр)
- Если вы установите значение N Long переменных
128
( не кэшируется ), у вас будет экземпляр объекта, на который указывает каждая ссылка. (N переменных, N экземпляров)
Вот почему это:
Long val1 = 127L;
Long val2 = 127L;
System.out.println(val1 == val2);
Long val3 = 128L;
Long val4 = 128L;
System.out.println(val3 == val4);
Выводит это:
правда
ложь
Для значения 127L , поскольку обе ссылки (val1 и val2) указывают на один и тот же экземпляр объекта в памяти (кэшированном), оно возвращается true
.
С другой стороны, для значения 128 , поскольку нет экземпляра для него, кэшированного в памяти, создается новый для любых новых назначений для значений в штучной упаковке, в результате чего создаются два разных экземпляра (на которые указывает val3 и val4) и возвращается false
на сравнение между ними.
Это происходит исключительно потому, что вы сравниваете с оператором две Long
объектные ссылки , а не long
примитивные значения ==
. Если бы не этот механизм кеширования, эти сравнения всегда не выполнялись бы , поэтому настоящая проблема здесь заключается в сравнении значений в штучной упаковке с помощью ==
оператора.
Изменение этих переменных на примитивные long
типы предотвратит это, но в случае, если вам нужно сохранить свой код с использованием Long
объектов, вы можете безопасно провести эти сравнения с помощью следующих подходов:
System.out.println(val3.equals(val4)); // true
System.out.println(val3.longValue() == val4.longValue()); // true
System.out.println((long)val3 == (long)val4); // true
(Правильная проверка нуля необходима даже для отливок)
ИМО , всегда рекомендуется использовать методы .equals () при сравнении объектов.
Справочные ссылки:
.longValue()
.При сравнении непримитивов (также известных как объекты) в Java
==
сравниваются их ссылки, а не их значения.Long
- это класс, и поэтомуLong
значения - это объекты.Проблема заключается в том, что Java Разработчики хотели , чтобы люди используют ,
Long
как они используютсяlong
для обеспечения совместимости, что привело к концепции Autoboxing, которая, по существу , особенность, чтоlong
-значения будут изменены наLong
-Объекты и наоборот по мере необходимости. Однако поведение автобокса не всегда точно предсказуемо, поскольку оно не определено полностью.Чтобы быть в безопасности и иметь предсказуемые результаты, всегда используйте
.equals()
для сравнения объектов и не полагайтесь на автобокс в этом случае:источник