Гарантировано ли, что новый 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

Сначала я объясню, когда == является ссылочным равенством и именно тогда, когда это числовое равенство. Условия для ссылочного равенства проще, поэтому сначала будет объяснено.

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
  • поэтому == - операция численного равенства

Резюме

  • Если оба операнда == и != являются ссылочными типами, это всегда будет эталонная операция равенства
    • Не имеет значения, конвертируются ли операнды в числовые типы
  • Если хотя бы один из операндов является числовым типом, он всегда будет выполнять численное равенство
    • При необходимости будет выполняться автоматическая распаковка одного (не более!) операндов

Ссылки

Связанные вопросы