Что именно делает сравнение целых чисел с ==?

РЕДАКТИРОВАТЬ: ОК, хорошо, я неправильно прочитал. Я не сравниваю int с целым числом. Верно подмечено.

Моя книга SCJP гласит:

Когда == используется для сравнения примитива с оберткой, обертка будет развернута и сравнение будет примитивом примитива.

Итак, вы думаете, что этот код будет печатать true:

    Integer i1 = 1; //if this were int it'd be correct and behave as the book says.
    Integer i2 = new Integer(1);
    System.out.println(i1 == i2);

но это печатает false,

Также, согласно моей книге, это должно напечатать true:

Integer i1 = 1000; //it does print `true` with i1 = 1000, but not i1 = 1, and one of the answers explained why.
Integer i2 = 1000;
System.out.println(i1 != i2);

Нету. Это false,

Что дает?

7 ответов

Решение
Integer i1 = 1;
Integer i2 = new Integer(1);
System.out.println(i1 == i2);

Когда вы назначаете 1 для i1 это значение в штучной упаковке, создавая Integer объект. Затем сравнение сравнивает две ссылки на объекты. Ссылки неравны, поэтому сравнение не удается.

Integer i1 = 100;
Integer i2 = 100;
System.out.println(i1 != i2);

Поскольку они инициализируются с помощью констант времени компиляции, компилятор может и выполняет их, и указывает на одно и то же Integer объект.

(Обратите внимание, что я изменил значения с 1000 на 100. Как указывает @NullUserException, интернируются только маленькие целые числа.)


Вот действительно интересный тест. Посмотрим, сможешь ли ты понять это. Почему первая программа печатает true, но второй false? Используя свои знания по боксу и анализу времени компилятора, вы сможете понять это:

// Prints "true".
int i1 = 1;
Integer i2 = new Integer(i1);
System.out.println(i1 == i2);

// Prints "false".
int i1 = 0;
Integer i2 = new Integer(i1);
i1 += 1;
System.out.println(i1 == i2);

Если вы понимаете вышесказанное, попробуйте предсказать, что печатает эта программа:

int i1 = 0;
i1 += 1;
Integer i2 = new Integer(i1);
System.out.println(i1 == i2);

(После того, как вы угадаете, запустите его и посмотрите!)

Также обратите внимание, что более новые версии кеша Java Integers в диапазоне от -128 до 127 (256 значений), что означает, что:

Integer i1, i2;

i1 = 127;
i2 = 127;
System.out.println(i1 == i2);

i1 = 128;
i2 = 128;
System.out.println(i1 == i2);

Будет печатать true а также false, (см. на Ideone)

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

Вы можете положиться на распаковку при использовании == сравнить упакованный примитив с примитивом (например: Integer с int), но если вы сравниваете два Integerс == это не удастся по причинам, объясненным @dan04.

Вы не сравниваете примитив с оберткой. Вы сравниваете две обертки (ссылочные типы). == сравнивает идентификатор объекта, который возвращает false потому что они разные объекты.

Обратите внимание, что вы неправильно прочитали цитату, которую вы цитировали. Отрывок специально ограничивает это утверждение сравнениями, подобными этим:

int k = 1;
Integer l = new Integer(1);
System.out.println(l == k);

Нет, я бы не подумал, что этот код напечатан верно, и вы сами ответили, почему.

Когда == используется для сравнения примитива с оберткой, обертка будет развернута и сравнение будет примитивом примитива.

Затем вы сравнили две целочисленные ссылки, то есть сравнили адреса памяти i1 и i2. Вы хотели либо

Integer i1 = 1;
Integer i2 = new Integer(1);
System.out.println(i1.equals(i2));

Или же

int i1 = 1;
Integer i2 = new Integer(1);
System.out.println(i1 == i2);

Начиная с Java 5.0, есть автоматическая упаковка и распаковка, что означает, что обертки могут быть неявно преобразованы в примитивы и наоборот. Однако, если вы сравниваете два объекта Integer, вы все равно сравниваете две ссылки, и нет ничего, что могло бы вызвать автоматическую упаковку / распаковку. Если бы это было так, код, написанный на J2SE 1.4 и более ранних версиях, сломался бы.

Пусть пусть есть пример

Каким будет вывод этого программного кода?

public class autoboxing {
public static void main(String a args) {
Integer a = new Integer(127);
Integer b = new Integer(127);
Integer c = 127;
Integer d = 127;
Integer e = new Integer(200);
Integer f = new Integer(200);
Integer g = 200;
Integer h = 200;
System.out.println((a == b) + ' " + (c =-- d) + " " + (e==f)+ " "+ (g == h));

,

Когда вы создаете объект Integer с новым оператором, он каждый раз возвращает новый объект. Когда вы сравниваете две ссылочные переменные с оператором "==", если две ссылочные переменные ссылаются на два разных объекта, оператор "==" возвращает false.

Так,

(a == b) и (e==f) выражения возвращают false. Целочисленный класс кэширует значения в диапазоне от -128 до 127.

Когда вы сравниваете два целочисленных объекта с оператором "==", если эти два целочисленных объекта создаются с помощью автобокса, будет вызван метод value0f (int i).

ОТВЕТ: Ложь Правда Ложь Ложь

Ниже приведена реализация этого метода

public static Integer value0f(int i) {
if (i >= IntegerCachedow && i <= IntegerCache.high)
return IntegerCache.cacheli + (-IntegerCachedow));
return new Integer(i);

Из приведенной выше реализации, ниже приведены выводы

  1. Если значения двух объектов Integer находятся в диапазоне от -128 до 127, этот метод возвращает одинаковые значения. Так что (c == d) возвращает true.

  2. Если два значения объектов Integer находятся за пределами диапазона от -128 до 127, этот метод возвращает различные новые объекты Integer. Итак, (g == h) возвращает false

Более подробно о методе здесь: https://stackru.com/questions/20897020/why-integer-class-caching-values-in-the-range-128-to-127

Другие вопросы по тегам