方法返回类型 Object 中的 NullPointerException
NullPointerException in method returning type Object
为什么下面会抛出 NullPointerException? :
public static Object myTest() {
boolean x = false;
boolean y = false;
return x && y ? new Object() : x ? x : y ? y : null;
}
public static void main(String [ ] args) {
myTest();
}
我知道如果我执行以下任一操作,代码将不会抛出 NullPointerException:
A)
public static Object myTest() {
boolean x = false;
boolean y = false;
return x && y ? new Object() : x ? x : y ? y : (Object) null;
}
public static void main(String [ ] args) {
myTest();
}
B)
public static Object myTest() {
Boolean x = false;
Boolean y = false;
return x && y ? new Object() : x ? x : y ? y : null;
}
public static void main(String [ ] args) {
myTest();
}
此外,如果我完全更改代码并执行以下操作,它会起作用:
public static Object myTest() {
boolean x = false;
boolean y = false;
if(x && y) {
return new Object();
} else if(x) {
return x;
} else if(y) {
return y;
} else {
return null;
}
}
public static void main(String [ ] args) {
myTest();
}
我猜编译器正在做某种优化并以某种方式搞砸了?我假设这是某种转换问题,但为什么在这种情况下会抛出 NullPointerException 而不是 ClassCastException?任何关于为什么会发生这种情况的信息将不胜感激!
提前致谢
如果为可读性添加一些括号:
return (x && y) ? (new Object()) : (x ? x : (y ? y : null));
您可以看到,在 y ? y : null
,编译器将尝试拆箱 null
(以便类型匹配),导致抛出 NPE。
(这段代码不可读,可能应该避免。)但实际回答:
如上所述,推理与自动装箱和拆箱以及编译器进行检查有关。这就好像你写了 boolean b = (Boolean) null
,它在运行时会抛出一个 NPE。
在示例 A 中,您将其显式转换为对象,因此没有添加自动装箱。
在示例 B 中,一切都已经是一个对象(布尔值是一个原始值,而布尔值是一个对象),所以同样,没有装箱或拆箱。
最后,在示例 C 中,根本没有拆箱,而是在返回结果时只是装箱。 (if-else 分支允许编译器单独检查每个分支,而不是需要弄清楚整个语句然后为整个语句分配一个类型的三元运算符。这与语句 vs 表达式和一大堆奇怪的事情有关在 Java 自动装箱和类型检查规则中。)
(如果您尝试不兼容的转换,例如 (Boolean) 7
或在运行时,如果您执行以下操作,则会在编译时发生转换问题:
int c = 7;
Object co = (Object) c;
Boolean bco = (Boolean) co;
为什么下面会抛出 NullPointerException? :
public static Object myTest() {
boolean x = false;
boolean y = false;
return x && y ? new Object() : x ? x : y ? y : null;
}
public static void main(String [ ] args) {
myTest();
}
我知道如果我执行以下任一操作,代码将不会抛出 NullPointerException:
A)
public static Object myTest() {
boolean x = false;
boolean y = false;
return x && y ? new Object() : x ? x : y ? y : (Object) null;
}
public static void main(String [ ] args) {
myTest();
}
B)
public static Object myTest() {
Boolean x = false;
Boolean y = false;
return x && y ? new Object() : x ? x : y ? y : null;
}
public static void main(String [ ] args) {
myTest();
}
此外,如果我完全更改代码并执行以下操作,它会起作用:
public static Object myTest() {
boolean x = false;
boolean y = false;
if(x && y) {
return new Object();
} else if(x) {
return x;
} else if(y) {
return y;
} else {
return null;
}
}
public static void main(String [ ] args) {
myTest();
}
我猜编译器正在做某种优化并以某种方式搞砸了?我假设这是某种转换问题,但为什么在这种情况下会抛出 NullPointerException 而不是 ClassCastException?任何关于为什么会发生这种情况的信息将不胜感激!
提前致谢
如果为可读性添加一些括号:
return (x && y) ? (new Object()) : (x ? x : (y ? y : null));
您可以看到,在 y ? y : null
,编译器将尝试拆箱 null
(以便类型匹配),导致抛出 NPE。
(这段代码不可读,可能应该避免。)但实际回答:
如上所述,推理与自动装箱和拆箱以及编译器进行检查有关。这就好像你写了 boolean b = (Boolean) null
,它在运行时会抛出一个 NPE。
在示例 A 中,您将其显式转换为对象,因此没有添加自动装箱。
在示例 B 中,一切都已经是一个对象(布尔值是一个原始值,而布尔值是一个对象),所以同样,没有装箱或拆箱。
最后,在示例 C 中,根本没有拆箱,而是在返回结果时只是装箱。 (if-else 分支允许编译器单独检查每个分支,而不是需要弄清楚整个语句然后为整个语句分配一个类型的三元运算符。这与语句 vs 表达式和一大堆奇怪的事情有关在 Java 自动装箱和类型检查规则中。)
(如果您尝试不兼容的转换,例如 (Boolean) 7
或在运行时,如果您执行以下操作,则会在编译时发生转换问题:
int c = 7;
Object co = (Object) c;
Boolean bco = (Boolean) co;