Сравнение длинных значений в штучной упаковке 127 и 128

Я хочу сравнить два значения Long с использованием условий if. Когда эти значения меньше 128, условие if работает правильно, но когда они больше или равно 128, сравнение не выполняется.

Пример:

Long num1 = 127;
Long num2 = 127;

if (num1 == num2) {
    // Works ok
}

Сравнение приведенного выше кода работает правильно, но в коде ниже не работает:

Long num1 = 128;
Long num2 = 128;

if (num1 == num2) {
    // Does NOT work
}

Почему возникает проблема сравнения переменных Long со значениями больше 127? Если переменные типы данных изменяются на длинные примитивы, то сравнения выполняются для всех случаев.

Ответ 1

TL; DR

Java кэширует упакованные экземпляры -128 от -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

(Правильная проверка нуля необходима даже для кастингов)

IMO, всегда хорошая идея придерживаться методов .equals() при работе с объектными сравнениями.

Ссылочные ссылки:

Ответ 2

num1 и num2 - длинные объекты. Вы должны использовать equals() для их сравнения. == сравнение может иногда срабатывать из-за того, как JVM блокирует примитивы, но не зависит от него.

if (num1.equals(num1))
{
 //code
}

Ответ 3

Java кэширует примитивные значения от от -128 до 127. Когда мы сопоставляем два Long объекта, java внутренне вводит их в примитивное значение и сравнивает его. Но выше 127 объект Long не получит касту. Java кэширует вывод методом .valueOf().

Это кеширование работает для Byte, Short, Long от -128 до 127. Для кеширования Integer От -128 до java.lang.Integer.IntegerCache.high или 127, в зависимости от того, что больше. (Мы можем установить значение верхнего уровня, до которого значения Integer должны кэшироваться с помощью java.lang.Integer.IntegerCache.high).

 For example:
    If we set java.lang.Integer.IntegerCache.high=500;
    then values from -128 to 500 will get cached and 

    Integer a=498;
    Integer b=499;
    System.out.println(a==b)

    Output will be "true".

Объекты Float и Double никогда не кэшируются.

Символ получит кеш от 0 до 127

Вы сравниваете два объекта. поэтому оператор == проверяет равенство ссылок на объекты. Существуют следующие способы сделать это.

1) введите оба объекта в примитивные значения и сравните

    (long)val3 == (long)val4

2) прочитайте значение объекта и сравните

    val3.longValue() == val4.longValue()

3) Используйте метод equals() для сравнения объектов.

    val3.equals(val4);  

Ответ 4

Сравнение не-примитивов (aka Objects) в Java с == сравнивает их ссылку вместо их значений. Long - это класс, и поэтому значения Long являются объектами.

Проблема заключается в том, что разработчики Java хотели, чтобы люди использовали Long, как они использовали Long для обеспечения совместимости, что привело к концепции автобоксинга, которая по сути является функцией, что значения Long будут изменены to Long -Objects и наоборот при необходимости. Поведение автобоксинга не всегда предсказуемо все время, хотя, поскольку оно не полностью определено.

Чтобы быть в безопасности и иметь предсказуемые результаты, всегда используйте .equals() для сравнения объектов и не полагайтесь на автобоксинг в этом случае:

Long num1 = 127, num2 = 127;
if(num1.equals(num2)) { iWillBeExecutedAlways(); }