Неисправное поведение в Java в условном выражении - PullRequest
2 голосов
/ 28 июня 2011

Простое выражение:

Object val = true ? 1l : 0.5;

Какой тип val ? Ну, логически, val должен быть Long объектом со значением 1 . Но Java считает, что val является Double со значением 1.0 .

Это не относится ни к чему с автобоксом как

Object val = true ? new Long(1) : new Double(0.5);

результаты с таким же поведением.

Просто чтобы уточнить:

Object val = true ? "1" : 0.5;

приводит к правильной String .

Кто-нибудь может объяснить мне, почему они определили это так? Мне кажется, что это очень плохо спроектировано или действительно ошибка.

Ответы [ 5 ]

7 голосов
/ 28 июня 2011

Это описано в спецификации языка Java Раздел 15.25 (соответствующие части выделены жирным шрифтом):

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

  1. Если второй и третий операнды имеют одинаковый тип [...]

  2. Если один из второго и третьего операндов имеет тип boolean [...]

  3. Если один из второго и третьего операндов имеет нулевой тип [...]

  4. В противном случае, если второй и третий операнды имеют типы , которые можно преобразовать (§5.1.8) в числовые типы, то существует несколько случаев:

    1. Если один из операндов имеет тип байта [...]

    2. Если один из операндов имеет тип T, где T является байтом, коротким или символом, [...]

    3. Если один из операндов имеет тип Byte [...]

    4. Если один из операндов имеет тип Short [...]

    5. Если один из операндов имеет тип; Символ [...]

    6. В противном случае двоичное числовое продвижение (§5.6.2) применяется к типам операндов, а тип условного выражения является продвинутым типом второго и третьего операндов. Обратите внимание, что двоичное числовое продвижение выполняет преобразование без коробки (§5.1.8) и преобразование набора значений (§5.1.13).

  5. В противном случае второй и третий операнды имеют типы S1 и S2 соответственно. Пусть T1 будет типом, который следует из применения преобразования в бокс для S1, и пусть T2 будет типом, который следует из применения преобразования в бокс в S2. Тип условного выражения является результатом применения преобразования захвата (§5.1.10 ) до lub (T1, T2) (§15.12.2.7).

"lub", упомянутый в последнем абзаце, обозначает наименьшая верхняя граница и относится к наиболее конкретному супертипу, обычному для T1 и T2.


Что касается случая с Object val = true ? 1l : 0.5;, я согласен, что было бы более точным, если бы он применил правило 5 (для значений в штучной упаковке). Я предполагаю, что правила станут двусмысленными (или даже более сложными), если принять во внимание автобокс. К какому типу относится, например, выражение b ? new Byte(0) : 0.5?

Однако вы можете заставить его использовать правило 5, выполнив

Object val = false ? (Number) 1L : .5;
4 голосов
/ 28 июня 2011

Поскольку выражение должно иметь тип.

Если вы выполните 1l + 0,5d, вы закончите с 1,5d, потому что компилятор автоматически меняет типы на типы, которые могут позволить все возможные результаты.

В вашем случае компилятор видит? и присваивает результат выражения double, используя то же правило (вы можете написать long как double, но не все double как long).

1 голос
/ 28 июня 2011

Когда вы пишете

Object val = true ? new Long(1) : new Double(0.5);

, вы должны учитывать, что

(new Long(1) : new Double(0.5))

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

1 голос
/ 28 июня 2011

Это не недостаток дизайна:
Компилятор должен определить тип всего выражения true ? 1l : 0.5. Он пытается использовать тип, в котором требуется как можно меньше преобразований.
Поскольку 0.5 не вписывается в long (без потери точности), результат выражения не может быть длинным - следовательно, он должен быть double, а long просто конвертируется (без потери точности).

Обратите внимание, что вы не можете иметь выражение, условно имеющее разные типы - третичное выражение должно преобразовываться в того же типа независимо от условия.

Во втором фрагменте Object является единственным совместимым типом - Double получает коробку и String можно просто назначить.

0 голосов
/ 28 июня 2011

Я не могу предоставить вам вескую причину, но тип выражения определяется спецификацией языка Java: http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.25

В JLS все числовые типы рассматриваются как особые случаи.

...