Подтвердить что ты не робот

Почему результат условного оператора противоположный ожидаемому?

Object myObject = true ? new Integer(25) : new Double(25.0);

System.out.println(myObject);

Странно, он выводит 25.0 вместо 25

Что происходит?

4b9b3361

Ответ 1

Ваш код возвращает второй операнд (new Integer(25)), как вы ожидали, но преобразует его в Double из-за следующих правил.

Вот что JLS 15.25 говорит:

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

  • Если один из операндов имеет тип байта или байт, а другой имеет тип short или Short, то тип условного выражения является коротким.
  • Если один из операндов имеет тип T, где T является байтом, коротким или char, а другой операнд является константным выражением (§15.28) типа int, значение которого представляется в типе T, тогда тип условного выражения T.
  • Если один из операндов имеет тип T, где T - это Byte, Short или Character, а другой операнд является константным выражением (§15.28) типа int, значение которого представляется в типе U, который является результатом применения преобразования unboxing в T, то тип условного выражения равен U.
  • В противном случае для типов операндов применяется двоичное числовое продвижение (§5.6.2), а тип условного выражения - продвинутый тип второго и третьего операндов.
    Обратите внимание, что двоичное числовое продвижение выполняет преобразование набора значений (§5.1.13) и может выполнять преобразование для распаковки (§5.1.8).

И числовое продвижение:

5.6.2. Двоичное числовое продвижение

Когда оператор применяет двоичное числовое продвижение к паре операндов, каждый из которых должен обозначать значение, которое можно конвертировать в числовой тип, применяются следующие правила, чтобы:

Если какой-либо операнд имеет ссылочный тип, он подвергается распаковке преобразования (§5.1.8).

Расширение примитивного преобразования (§5.1.2) применяется для преобразования одного или обоих операндов, как указано в следующих правилах:

Если один из операндов имеет тип double, другой преобразуется в double.

В вашем примере у вас есть Integer и Double. Они распаковываются в int и Double, а затем int преобразуется в Double.

Ответ 2

Происходит какое-то странное автообновление - вы можете увидеть его лучше, если вы используете разные номера:

    Object myObject = true ? new Integer(25) : new Double(22.0);

Теперь myObject по-прежнему будет присвоен двойной (25.0), а не 22.0, который вы ожидаете, если условие не работает. В принципе, поскольку Java думает, что вы выполняете какой-то расчет, включающий int и double, он возвращает результат iif как "двойной" примитив, а затем автоматически возвращает его обратно в Double().

Вы также можете заставить его вести себя так, как ожидалось, заставляя его обрабатывать значения как тип Object():

    Object myObject = true ? (Object) new Integer(25) : (Object) new Double(22.0);

Ответ 3

После компиляции

Object myObject = true ? new Integer(25) : new Double(25.0);

будет что-то ниже

Object myObject = (double) new Integer(25);

Итак, он возвращает новый Integer (25), как и ожидалось, но он преобразуется в double.

Как сказал Эран, согласно JLS 5.6.2:

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

  • Если какой-либо операнд имеет ссылочный тип, он подвергается распаковке преобразования (§5.1.8).
  • Расширение примитивного преобразования (§5.1.2) применяется для преобразования одного или обоих операндов, как указано в следующих правилах:

    • Если один из операндов имеет тип double, другой преобразуется в double.

    • В противном случае, если любой операнд имеет тип float, другой преобразуется плавать.

    • В противном случае, если один из операндов имеет тип long, другой преобразуется долго.

    • В противном случае оба операнда преобразуются в тип int.