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