Гарантировано ли, что новый Integer (i) == я в Java?
Рассмотрим следующий фрагмент:
int i = 99999999;
byte b = 99;
short s = 9999;
Integer ii = Integer.valueOf(9); // should be within cache
System.out.println(new Integer(i) == i); // "true"
System.out.println(new Integer(b) == b); // "true"
System.out.println(new Integer(s) == s); // "true"
System.out.println(new Integer(ii) == ii); // "false"
Очевидно, что последняя строка будет ВСЕГДА печатать "false"
: мы используем сопоставление сравнения ссылок ==
, а объект new
будет НИКОГДА ==
к уже существующему объекту.
Вопрос о первых трех строках: эти сравнения гарантированы, чтобы быть на примитиве int
, с Integer
auto-unboxed? Существуют ли случаи, когда примитив был бы автоматически помещен в коробку, и выполнялись сравнительные сравнения идентичности? (что тогда было бы тогда false
!)
Ответы
Ответ 1
Да. JLS §5.6.2 определяет правила для двоичной цифровой рекламы. Частично:
Когда оператор применяет двоичный код числовое продвижение на пару операндов, каждый из которых должен обозначать значение, которое можно конвертировать в числовое типа, применяются следующие правила: порядок, с использованием расширяющегося преобразования (§5.1.2) для преобразования операндов в виде необходимо:
Если какой-либо из операндов имеет ссылочный тип, преобразование распаковки (П. 5.1.8).
Двоичное числовое продвижение применяется для нескольких числовых операторов, включая "операторы численного равенства == и! =."
JLS §15.21.1 (Операторы числового равенства == и! =) указывает:
Если операнды равенства оператор имеют как числовой тип, так и один имеет числовой тип, а другой является конвертируемой (п. 5.1.8) в числовой тип, двоичное числовое продвижение выполняются над операндами (§5.6.2).
В отличие от JLS §15.21.3 (равенство ссылок Операторы == и! =) Обеспечивает:
Если операнды равенства операторы являются либо справочными тип или нулевой тип, то операция - это равенство объектов
Это соответствует общему пониманию бокса и распаковки, что оно выполняется только при несоответствии.
Ответ 2
Сначала я объясню, когда ==
является ссылочным равенством и именно тогда, когда это числовое равенство. Условия для ссылочного равенства проще, поэтому сначала будет объяснено.
Если операнды оператора равенства являются либо ссылочным типом, либо нулевым типом, то операция является равенством объекта.
Это объясняет следующее:
System.out.println(new Integer(0) == new Integer(0)); // "false"
Оба операнда Integer
, которые являются ссылочными типами, и почему ==
является сопоставлением сравнения ссылок, а два объекта new
никогда не будут ==
друг для друга, поэтому почему он печатает false
.
Для ==
для численного равенства по крайней мере один из операндов должен быть числовым; это указано следующим образом:
Если операнды оператора равенства и числового типа, или один числового типа, а другой - конвертируемый в числовой тип, двоичное числовое продвижение выполняется в операндах. Если продвинутый тип операндов int
или long
, то выполняется целочисленный тест равенства; если продвинутый тип float or
double`, то выполняется тест равенства с плавающей запятой.
Обратите внимание, что двоичное числовое продвижение выполняет преобразование набора значений и преобразование распаковки.
Таким образом, рассмотрим следующее:
System.out.println(new Integer(0) == 0); // "true"
Отпечатает true
, потому что:
- правый операнд есть числовой
int
тип
- левый операнд преобразуется в числовой тип, распаковывая на
int
- поэтому
==
- операция численного равенства
Резюме
- Если оба операнда
==
и !=
являются ссылочными типами, это всегда будет эталонная операция равенства
- Не имеет значения, конвертируются ли операнды в числовые типы
- Если хотя бы один из операндов является числовым типом, он всегда будет выполнять численное равенство
- При необходимости будет выполняться автоматическая распаковка одного (не более!) операндов
Ссылки
Связанные вопросы