今天早上我遇到了一个非常奇怪的NPE,并将其简化为一个简单的例子。这是JVM错误还是正确行为?
public class Test1 {
class Item {
Integer id = null;
public Integer getId() {return id;}
}
public Integer f() {
Item item = new Item();
// this works:
//return item == null ? new Integer(1) : item.getId();
// NPE??
return item == null ? 1 : item.getId();
}
public static void main(String[] args) {
Test1 t = new Test1();
System.out.println("id is: " + String.valueOf(t.f()));
}
}
编译和运行的输出:
$ javac Test1.java
$ java Test1
Exception in thread "main" java.lang.NullPointerException
at Test1.f(Test1.java:12)
at Test1.main(Test1.java:16)
$
答案 0 :(得分:31)
表达式item == null ? 1 : item.getId()
的类型为int
而非Integer
。因此,Java需要将Integer
自动取消装箱到int
(导致NullPointerException
)。然后它会自动将结果返回到Integer
(如果不是NullPointerException
那么将)从方法返回。
另一方面,表达式item == null ? new Integer(1) : item.getId()
的类型为Integer
,无需自动取消装箱。
当您自动取消装箱null
Integer
时,您会收到NullPointerException
(请参阅Autoboxing),这就是您所遇到的问题。
要回答您的问题,这是正确的行为。
答案 1 :(得分:3)
item
可能不是null
,但是当您致电getId()
时,就会返回null
。当您尝试自动取消装箱null
时,您会获得一个NPE。
答案 2 :(得分:3)
如果您反编译该类文件,您将清楚地看到您的NPE ......
return Integer.valueOf(item != null ? item.getId().intValue() : 1);
答案 3 :(得分:2)
以下返回类型为Integer
-
public Integer f() {
Item item = new Item();
// this works:
//return item == null ? new Integer(1) : item.getId();
// NPE??
return item == null ? 1 : item.getId();
}
以下结果 -
item == null ? 1 : item.getId()
在你的情况下,是null
。
因此,JVM正在抛出NPE,因为它正在尝试自动装箱null
。
尝试 -
new Integer(null); // and
Integer.valueOf(null);
两者都会抛出NPE。
答案 4 :(得分:2)
之所以发生这种情况,是因为您使用的是条件运算符?
。线
return item == null ? 1 : item.getId();
相当于
int result = item == null ? 1 : item.getId();
return result;
结果是int,因为表达式中的第一个操作数。当您使用Integer显式换行1时,这就是您的代码工作的原因。在这种情况下,编译器会创建类似
的内容Integer result = item == null ? new Integer(1) : item.getId();
return result;
因此,NPE在尝试将item.getId()(即null)“强制转换”为int时发生。