Почему компилятор Java допускает приведение null к примитивному типу в тернарном операторе
Эта маленькая программа бросает NullPointerException
на линии троичного оператора:
public class Main {
int someMethod() {
return (true ? null : 0);
}
public static void main(String[] args) {
Main obj= new Main();
obj.someMethod();
}
}
Я понимаю причина в null
не может быть приведен к int
,
Однако вопрос заключается в том, почему компилятор Java допускает передачу такого рода кода, в то время как что-то подобное ниже приведет к ошибке времени компиляции:
int i = null; //Error: incompatible types: <nulltype> cannot be converted to int
2 ответа
Согласно спецификации языка Java - условный оператор, Java будет оценивать условное выражение во время выполнения, а не во время компиляции. Вот почему ошибка не обнаружена во время компиляции:
Во время выполнения первое выражение операнда условного выражения вычисляется первым. Полученное логическое значение затем используется для выбора второго или третьего выражения операнда.
Итак, в вашем случае:
int someMethod() {
return (true ? null : 0);
}
изображений true
является методом, содержащим сложную логику, и имеет смысл, если Java вычисляет 1-й операнд (в данном случае true
) во время выполнения. Затем на основании правила:
Если один из второго и третьего операндов имеет примитивный тип T, а тип другого является результатом применения преобразования в бокс (§5.1.7) к T, то тип условного выражения - T.
С 3-го операнда 0
тип примитива (T), тип выражения будет тип T (int
). Итак, распаковка нулевой ссылки на int
приведет к NPE.
Компилятор запрещает
int i = null;
потому что тип выражения null
является "нулевым типом", и для "нулевого типа" не существует правила преобразования распаковки. ( JLS раздел 5.1.8).
Тем не менее, разрешено писать:
int i = (Integer) null;
потому что выражение (Integer) null
имеет тип java.lang.Integer
и вызовет распаковку, что всегда приводит к исключению NullPointerException.
Когда вы пишете:
return (true ? null : 0);
в методе, который возвращает int
или просто когда пишешь:
int i = (true ? null : 0);
это компилируется. Тип (true ? null : 0)
является java.lang.Integer
и это становится похожим на int i = (Integer) null;
Вы должны отметить, что null
может быть "упакован" как Integer, Float, Double и т. д. в контексте троичного выражения (a ? b : c
). Это конкретно описано в JLS 5.1.7 (преобразования в боксы) и JLS 15.25 (условный оператор "?:").