Объект кода o = true? new Integer (0): new Long (1) возвращает Long со значением 0. Почему?

Пожалуйста, подумайте, что у нас есть код ниже:

Object obj = true ? new Integer(0) : new Long(1);
System.out.println(obj.getClass() + "\nvalue = " + obj);

И его результат:

class java.lang.Long
value = 0

Вместо:

class java.lang.Integer
value = 0

Может ли кто-нибудь уточнить, почему у нас есть такая функциональность на Java? Это очень странно для меня. Есть ли у вас пример, где это может быть полезно?

UPDATE: Вот фрагмент байт-кода, где мы можем видеть, что происходит там

NEW java/lang/Integer
DUP
LDC "0"
INVOKESPECIAL java/lang/Integer.<init> (Ljava/lang/String;)V
INVOKEVIRTUAL java/lang/Integer.intValue ()I
I2L
INVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;
ASTORE 1

Ответ 1

Здесь происходит результат

  • Двоичное числовое продвижение, превращающее типы Integer и Long в Long для использования в качестве общего типа для применения к условному выражению оператора
  • Unboxing те объекты оболочки
  • И затем бокс результирующего значения условного выражения

Условный оператор второго и третьего операндов должен иметь тот же тип, который является результирующим типом выражения. Integer и Long не являются, конечно, одним и тем же типом.

Однако, как описано в JLS§15.25, компилятор применит двоичное числовое продвижение при определении возможного общего типа для применения к выражению. Этот раздел имеет удобную таблицу 15.25-D, которая говорит нам, что, когда второй операнд имеет тип Integer, а третий операнд имеет тип Long, компилятор будет выполнять двоичное числовое продвижение по Integer,Long. Двоичное числовое продвижение по Integer,Long дает Long. Таким образом, результат условного выражения оператора Long.

Так как тип результата выражения Long, Integer или Long должен быть распакован (а затем брошен, в случае Integer).

Наконец, вы назначаете его Object, который заставляет бокс и обертывает Long в Long. Таким образом, вы получаете Long, содержащее значение 0, которое соответствует вашему результату.

Таким образом, если мы проигнорируем тот факт, что компилятор оптимизирует половину следующих действий, поскольку он имеет дело с постоянным выражением, благодаря true в коде (я использовал вместо него flag), этот код заканчивается тем, что:

Object obj = Long.valueOf(flag ? (long)(new Integer(0)).intValue() : (new Long(1)).longValue());
System.out.println(obj.getClass() + "\nvalue = " + obj);
  • (long)(new Integer(0)).intValue() представляет unboxing Integer и отбрасывает его на Long, чтобы он соответствовал типу результата выражения.
  • (new Long(1)).longValue() представляет unboxing Long, чтобы он соответствовал типу результата выражения.
  • И Long.valueOf представляет бокс в конце.

Ответ 2

Это поведение хорошо объяснено в JLS - 15.25. Условный оператор?::

Условный оператор имеет три выражения операнда. ? появляется между первым и вторым выражениями, а : появляется между вторым и третьим выражениями.

[...]

Тип условного выражения определяется следующим образом:

  • [...]

  • В противном случае, если второй и третий операнды имеют типы, которые конвертируются (§5.1.8) в числовые типы, тогда существует несколько случаев:

    • [...]

    • В противном случае для типов операндов применяется двоичное числовое продвижение (§5.6.2), а тип условного выражение является продвинутым типом второго и третьего операндов.

Ответ 3

На самом деле long может хранить значение целого числа, но целое число не может хранить значение long (концепция расширяется), и вы сохраняете его в Object, чтобы он хранил его в Long. внутренне он также использует бокс и распаковку

Возможный код компилятора:

Long obj = true ? new Integer(0) : new Long(1);

System.out.println(obj.getClass() + "\nvalue =" + obj);

Не работает код (не удается скомпилировать):

 Integer obj = true ? new Integer(0) : new Long(1);

System.out.println(obj.getClass() + "\nvalue =" + obj);

проверьте сами и сообщите мне, если у вас есть какие-либо сомнения в этом.

Ответ 4

Это связано с тем, как работает тернарный оператор.

Операнды с обеих сторон : должны быть совместимых типов, поэтому вы не можете этого сделать:

true ? 1 : "Hello"

Так как int и String не могут быть принудительно преобразованы друг в друга.

В вашем случае, однако, типы совместимы! int может быть неявно преобразован в long. И это то, что сделал компилятор! Он видел int и долго и решает, что выражение должно оцениваться до long. Он отключает два значения и принудительно преобразует int в long. И, наконец, он помещает результирующий long, поэтому он становится long и помещает его в переменную.