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

111

Я хочу сравнить значения двух длинных объектов с помощью 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 ? Если типы данных переменных изменяются на длинные примитивы , то сравнения работают для всех случаев.

Вирадж Дхамал
источник

Ответы:

212

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 () при сравнении объектов.

Справочные ссылки:

Everton
источник
15

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

Это кеширование работает для Byte, Short, Long от -128 до 127. Для целочисленного кеширования работает от -128 до java.lang.Integer.IntegerCache.high или 127, в зависимости от того, что больше. (Мы можем установить значение верхнего уровня, до которого целочисленные значения должен быть кэширован с помощью 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);  
Джей
источник
14

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

if (num1.equals(num1))
{
 //code
}
Nishan
источник
1
Это (что лучше) или сравните возвращаемое значение .longValue().
Джулио Франко
4

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

Проблема заключается в том, что Java Разработчики хотели , чтобы люди используют , Longкак они используются longдля обеспечения совместимости, что привело к концепции Autoboxing, которая, по существу , особенность, что long-значения будут изменены на Long-Объекты и наоборот по мере необходимости. Однако поведение автобокса не всегда точно предсказуемо, поскольку оно не определено полностью.

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

Long num1 = 127, num2 = 127;
if(num1.equals(num2)) { iWillBeExecutedAlways(); }
LionC
источник