В Java делает ли == Box или Unbox при сравнении объекта и постоянного значения?

При сравнении целочисленного объекта и постоянного значения упаковывает ли Java значение или распаковывает целочисленный объект?

На основании того, что я прочитал, «==» является сравнительным сравнением, поэтому логично предположить, что Java помещает константу в коробку для выполнения контрольного сравнения между объектами. Тем не менее, приведенный ниже тестовый код, похоже, дает противоречивые результаты.

Integer v1 = 1000;
Integer v2 = 1000;
boolean b1 = v1 == 1000; //True.
boolean b2 = v1 == v2; //False. Proof that 1000 boxes to new object and is not fetched from cache.

Так как же в Java работает сравнение объектов и констант с использованием ==? Сравнивает ли оператор по значению в этом случае?


person Amrish Kumar    schedule 04.03.2020    source источник
comment
использование Integer::valueOf(1000) дает вам шанс на кеширование.   -  person John3136    schedule 04.03.2020
comment
IIRC, JLS по умолчанию требует кэширования только 256 значений, т.е. от -128 до 127. Кроме того, Integer v1 = 1000; вызывает метод value0f внутри себя.   -  person Amrish Kumar    schedule 04.03.2020
comment
Гарантируется кэширование от -128 до 127, но может кэшироваться больше. Если вы используете valueOf, он может кэшировать, а может и нет - по крайней мере, есть шанс!   -  person John3136    schedule 05.03.2020
comment
Мне не нужно явно использовать метод valueOf. Бокс вызывает этот метод изнутри. Integer v1 = 1000; и Integer v1 = Integer.valueOf(1000); одинаковы, я знаю это по отладчику.   -  person Amrish Kumar    schedule 05.03.2020


Ответы (2)


То, что вы называете «постоянным значением», является литералом int, поэтому его тип - int.

JLS 15.21.1 говорит:

Если операнды оператора равенства имеют оба числового типа, или один имеет числовой тип, а другой может быть преобразован (§5.1.8) в числовой тип, двоичное числовое продвижение выполняется для операндов.

В вашем v1 == 1000 тесте 1000 имеет числовой тип, а v1 может быть преобразован в числовой тип, поэтому выполняется двоичное числовое продвижение.

JLS 5.6.2 (двоичное числовое продвижение) говорит:

Если какой-либо операнд имеет ссылочный тип, он подвергается преобразованию распаковки

Следовательно, операнд Integer - v1 - распаковывается в int, и выполняется сравнение двух int. Следовательно, результат сравнения true.

Когда вы сравниваете два ссылочных типа - v1 == v2 - распаковки не происходит, сравниваются только ссылки, как написано в JLS 15.21.3:

Если операнды оператора равенства имеют либо ссылочный тип, либо нулевой тип, тогда операция является равенством объектов.

Поскольку 1000 слишком велик для кэширования Integer кешем, b1 и b2 не ссылаются на один и тот же экземпляр, и поэтому результатом сравнения будет false.

person Eran    schedule 04.03.2020

Целочисленные пулы аналогичны пулу строк, но он кэширует значение, если целочисленные объекты находятся в диапазоне от -128 до 127. Поэтому, когда вы пытаетесь присвоить значение в этом диапазоне объекту-оболочке , операция упаковки вызовет метод Integer.valueOf и, в свою очередь, назначит ссылку на объект, который уже в пуле.

но если вы присвоите значение за пределами этого диапазона типу ссылки оболочки, Integer.valueOf создаст новый объект Integer < / strong> для этого значения. И, следовательно, сравнение ссылки на объекты Integer, значение которых выходит за пределы этого диапазона, даст вам false

Так что в вашем случае

Integer v1 = 1000;
Integer v2 = 1000;
boolean b1 = v1 == 1000; //True.
boolean b2 = v1 == v2; // out of range so it will false but if you use 127 instead of 1000 then it will true.

проверьте документацию здесь

person Negi Rox    schedule 04.03.2020