Object myObject = true ? new Integer(25) : new Double(25.0);
System.out.println(myObject);
Странно, он выводит 25.0 вместо 25
Что происходит?
Object myObject = true ? new Integer(25) : new Double(25.0);
System.out.println(myObject);
Странно, он выводит 25.0 вместо 25
Что происходит?
Ваш код возвращает второй операнд (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
.
Происходит какое-то странное автообновление - вы можете увидеть его лучше, если вы используете разные номера:
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);
После компиляции
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.