为什么这段Java代码会抛出NullPointerException?

3
为什么以下Java代码会抛出NullPointerException?
public static void main(String[] args) {
    getInteger(null);
}

public static Integer getInteger(Number n) {
    return (n == null || n instanceof Integer) ? (Integer)n : n.intValue();
}

编辑:我添加了括号,以消除关于“我是否有时返回布尔值”的困惑。


1
作为旁注,如果n为null,则n instanceof Integer也会失败,因此您基本上要检查两次。 - SomeJavaGuy
如果LHS条件为真,那么RHS会如何执行?如果我没错的话,如果LHS返回true,则不会进入RHS。这是一个非常好的问题,我很欣赏,但我发现有很多答案并且得到了赞同,但没有人解释我的疑问。请问有人能够解释一下吗,让我明白正确的情况是什么? - Vishal Gajera
3
请将 n.intValue() 改为 Integer.valueOf(n.intValue())(目前所有答案都不正确)。 - assylias
1
@assylias 谢谢您给出唯一正确的回答!Java自动拆箱起作用了...早该知道了。 - Hans Brende
3
@Tim,由于表达式的第二部分是 n.intValue(),它会返回一个原始的整数类型(primitive int),编译器也会对第一部分进行拆箱操作。因此,在编译后的代码中,(Integer) n 就变成了 ((Integer) n).intValue()。如果输入为 null,则会抛出 NPE 异常。希望这样解释清楚了。 - Codebender
显示剩余4条评论
2个回答

4

完全要归功于@assylias发现的答案。请改用以下代码:

public static Integer getInteger(Number n) {
    return (n == null || n instanceof Integer) ? (Integer)n : Integer.valueOf(n.intValue());
}

由于奇怪的装箱/拆箱规则,因为 n.intValue() 返回一个原始的 int,编译器也会将 n 在表达式 (Integer)n 中拆箱为原始类型。而且, null 不能被赋给原始类型(在你的 IDE 中尝试一下)。

编辑:

NPE 的真正原因并不是因为将 null 赋给了一个原始类型(编译器不会这样做),而是因为通过调用 Integer.intValue() 方法来执行拆箱操作,并且该方法在此情况下被调用时所针对的是一个 null 引用。


1
但这并没有告诉我为什么我的代码失败了。 - Hans Brende
是的,它确实会。在null的情况下,您试图在RHS表达式中返回一个布尔值。 - Tim Biegeleisen
3
@TimBiegeleisen,你不觉得IDE应该提醒用户这个语句可能会返回布尔值吗?我试过那段代码,我在想... - Danyal Sandeelo
@TimBiegeleisen 我编辑了我的问题,加上了括号,以消除关于返回布尔值的混淆。 - Hans Brende
1
@TimBiegeleisen,问题在于两者都被解封为int。 - Hans Brende
显示剩余6条评论

0

因为在这里:

return n == null || n instanceof Integer ? (Integer)n : n.intValue();
                                             here

你正在尝试将 null 值的 n 转换为整数。


1
但是 null 可以转换为 Integer。 - Hans Brende
@KostasC 大家都知道由于大小写问题导致的时间抛出 NullPointerException,但是如果看到 n== null 返回 true,那么它如何移动到短路 OR 运算符的右侧。 - Vishal Gajera
如果LHS条件为真,则RHS如何在计算机上执行,如果我没错的话,那么如果LHS返回true,则不会进入RHS。 - Vishal Gajera
1
此答案不正确...请参见副本。 - assylias
1
@assylias 感谢您的纠正。 - Gaurav Jeswani
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接