Java: тернарный оператор, нюансы его работы

172
13 апреля 2018, 18:06

Пусть имеем такой код:

System.out.print((true ? 1 : null).getClass().getSimpleName());

Все скомпилируется и результат будет

Integer

Залезая в документацию по тернарному оператору, имеем:

The type of a conditional expression is determined as follows:

If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.

If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.

If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.

Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:

  • If one of the operands is of type byte or Byte and the other is of type short or Short, then the type of the conditional expression is short.

  • If one of the operands is of type T where T is byte, short, or char, and the other operand is a constant expression (§15.28) of type int whose value is representable in type T, then the type of the conditional expression is T.

  • If one of the operands is of type T, where T is Byte, Short, or Character, and the other operand is a constant expression (§15.28) of type int whose value is representable in the type U which is the result of applying unboxing conversion to T, then the type of the conditional expression is U.

  • Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands.

  • Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).

Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2.

The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1, T2) (§15.12.2.7).

Источник

Я выделил жирным два пункта, которые, как мне кажется, могут иметь отношение к происходящему в примере. Вопрос, что именно происходит и как в данном случае?

Первый выделенный пункт - типа компилятор пытается применить эти правила, видит, что один из операндов null.. но второй то int, дай ка я его автоупакую и будет ссылочным типом. И таком образом, результирующий тип по правилу становится Integer.

Но почему тогда момент "дай ка я его автоупакую и будет ссылочным типом" не указан в правиле? Может быть это подразумевается, так как такое поведение описано еще где-либо?

Или здесь все же применимо второе выделенное правило? Честно, я с ним еще не разобрался, там довольно много чтива и несколько раз надо по ссылкам в процессе понимания перескакивать, это будет небыстро. А именно, что такое "capture conversation" и "lub(T1, T2)".

Но я уже не могу понять, мы имеем, что S1 == int type, S2 == null type, тогда T1 == Integer, но что тогда с null и чем является T2? Т.е. получается, это правило не применимо.

Интересует, что же именно тут происходит?

Answer 1

Дело в том, что тернарный оператор выбирает тип из рантайма в зависимости от условия. Следовательно соответствующее пробразование типов выполняется к исходному выражению. Поскольку у вас true в выражении, то второй операнд просто не используется и преобразование типов не осуществляется.

Но я уже не могу понять, мы имеем, что S1 == int type, S2 == null type, тогда T1 == Integer, но что тогда с null и чем является T2? Т.е. получается, это правило не применимо.

Совершенно верно, поскольку правило использует оба выражения, а у вас оно одно.

Answer 2

второе, по логике и экспериментально, потому что

System.out.print((true ? 1 : new Object()).getClass().getSimpleName());

тоже выдает Integer

дополнене:

    System.out.println((true ? 1 : null).getClass().getSimpleName());
    System.out.println((true ? 1 : new Object()).getClass().getSimpleName());
    System.out.println((false ? 1 : new Object()).getClass().getSimpleName());
    System.out.println((true ? 1 : new String()).getClass().getSimpleName());
    System.out.println((false ? 1 : new String()).getClass().getSimpleName());
=>
Integer
Integer
Object
Integer
String
READ ALSO
как конвертировать int в 16 ричную систему?

как конвертировать int в 16 ричную систему?

Добрый день нужно на сервер отправлять данные ф формате 16 речной системы ASCIIК примеру -1 как FFFFFFFF соответсвенно -2 как FFFFFFFE

154
Правильная работа с ObserverList

Правильная работа с ObserverList

Всем приветВопрос про БД и JavaFX

179
Кракозябры в netty

Кракозябры в netty

Я только вникаю в netty, могу допустить серьёзные ошибки, не бейте тапками

141
Как работать с OCR библиотекой Google Vision(Mobile Vision)

Как работать с OCR библиотекой Google Vision(Mobile Vision)

Хочу сделать приложение которое бы сканировало числа и выводило их в приложениеИз библиотек я знаю Teseract, ABBYY, и Google Vision(Mobile Vision)

174