Порівнюючи коробочки Довгі значення 127 і 128


111

Я хочу порівняти два значення 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
}

Чому виникає проблема порівняння довгих змінних зі значеннями, що перевищують 127 ? Якщо типи даних змінних змінено на довгі примітиви , то порівняння працюють у всіх випадках.

Відповіді:


212

TL; DR

Java кешує в коробках цілі екземпляри від -128до 127. Оскільки ви використовуєте ==для порівняння посилань на об'єкти замість значень , відповідають лише кешовані об'єкти. Або працюйте з longнепоміченими примітивними значеннями або використовуйте .equals()для порівняння Longоб'єктів.

Довга (призначена для каламбуру) версія

Чому існує проблема порівняння змінної Long зі значенням, що перевищує 127? Якщо тип даних вищевказаної змінної є примітивним (довгим), то код працює для всіх значень.

Java кешує об'єкти об'єктів Integer з діапазону від -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 () при роботі з об'єктами порівнянь.

Довідкові посилання:


15

Java кешує примітивні значення від -128 до 127 . Коли ми порівнюємо два Довгі об'єкти, тип java внутрішньо видає його на примітивне значення та порівнює. Але вище 127 довгий об'єкт не отримає тип касти. Java кешує вихід методом .valueOf () .

Це кешування працює для байтів, коротких, довгих від -128 до 127. Для кешування Integer працює від -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
}

1
Це (що краще) або порівняти повернене значення .longValue().
Джуліо Франко

4

Порівнюючи непримітивні елементи (aka Objects) на Java з ==порівнянням їх посилання замість їх значень. Longє класом і, таким чином, Longзначення - Об'єкти.

Проблема полягає в тому, що розробники Java хотіли, щоб люди використовували так, Longяк раніше, longщоб забезпечити сумісність, що призвело до концепції автобоксингу, що є, по суті, особливістю, що long-значення будуть змінені на Long-об'єкти і навпаки, якщо потрібно. Поведінка автобоксингу не є точно передбачуваним весь час, хоча це не повністю визначено.

Отже, щоб бути безпечним і мати передбачувані результати, завжди використовуйте .equals()для порівняння об'єктів і не покладайтеся на автобокс в цьому випадку:

Long num1 = 127, num2 = 127;
if(num1.equals(num2)) { iWillBeExecutedAlways(); }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.