Рассмотрите следующий отрывок:
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"
: мы используем ==
ссылочное сравнение идентификационных данных и a new
объект никогда не будет ==
к уже существующему объекту.
Вопрос о первых 3 строках: те сравнения, которые, как гарантируют, будут на примитиве int
, с Integer
автораспакованный? Есть ли случаи, где примитив был бы автоупакован вместо этого, и ссылочные сравнения идентификационных данных выполняются? (который все затем был бы false
!)
Да. JLS §5.6.2 определяет правила для двоичного числового продвижения. Частично:
Когда оператор применяет двоичное числовое продвижение к паре операндов , каждый из которых должен обозначать значение , которое может быть преобразовано в числовое {{1 }} применяются следующие правила, в порядке , с использованием расширяющего преобразования (§5.1.2) для преобразования операндов в случае необходимости :
Если какой-либо из операндов имеет ссылочный тип , выполняется преобразование распаковки (§5.1.8).
Двоичное числовое продвижение применяется к нескольким числовым операторам, включая «операторы числового равенства == и! =».
JLS §15.21.1 (Операторы числового равенства == и! =) Определяет:
Если операнды оператора равенства имеют оба числового типа или один имеет числовой тип, а другой может быть преобразован (§5.1.8) в числовой {{ 1}}, двоичное числовое продвижение выполняется для операндов (§5.6.2).
Напротив, JLS §15.21.3 (Операторы эталонного равенства == и! =) Обеспечивает:
Если операнды оператора равенства оба относятся к любой ссылке { {1}} или нулевой тип, тогда операция - это равенство объектов
Это соответствует общепринятому пониманию упаковки и распаковки, это делается только при несоответствии.
Сначала я объясню именно тогда, когда ==
является ссылочным равенством, и именно тогда, когда это числовое равенство. Условия эталонного равенства проще, поэтому они будут объяснены в первую очередь.
==
и ! =
Если операнды оператора равенства либо ссылочного типа, либо типа null , то операция - равенство объектов.
Это объясняет следующее:
System.out.println(new Integer(0) == new Integer(0)); // "false"
Оба операнда - Integer
, которые являются ссылочными типами, поэтому ==
является сравнением ссылочного равенства, а два новых
объекты никогда не будут ==
друг к другу, поэтому он печатает false
.
Чтобы ==
было числовым равенством, по крайней мере один из операндов должен быть числового типа ; это определяется следующим образом:
==
и ! =
Если операнды оператора равенства оба числовых тип, или один является числового типа, а другой может преобразовываться в числовой тип, двоичное числовое продвижение выполняется для операндов. Если повышенный тип операндов -
int
илиlong
, то выполняется проверка на равенство целых чисел; если повышенный тип -float или
double`, то выполняется проверка на равенство с плавающей запятой.Обратите внимание, что двоичное числовое продвижение выполняет преобразование набора значений и преобразование распаковки.
Таким образом, рассмотрим следующее:
System.out.println(new Integer(0) == 0); // "true"
Это выводит true
, потому что:
int
тип int
==
является операцией числового равенства ==
и ! =
являются ссылочными типами, это всегда будет операция ссылочного равенства
==
и ! =
==
и ! =