为了账号安全,请及时绑定邮箱和手机立即绑定

为什么在Java中将Integer与int进行比较会抛出NullPointerException?

为什么在Java中将Integer与int进行比较会抛出NullPointerException?

繁星点点滴滴 2019-10-10 16:57:11
观察这种情况令我非常困惑:Integer i = null;String str = null;if (i == null) {   //Nothing happens   ...                  }if (str == null) { //Nothing happens}if (i == 0) {  //NullPointerException   ...}if (str == "0") { //Nothing happens   ...}因此,我认为装箱操作首先执行(即Java尝试从中提取int值null),而比较操作的优先级较低,这就是引发异常的原因。问题是:为什么要用Java这样实现?为什么装箱优先于比较参考?或者为什么他们没有null在装箱前实施验证?此刻,当NullPointerException它与包装的基元一起被抛出而与真实的对象类型没有被抛出时,它看起来不一致。
查看完整描述

3 回答

?
人到中年有点甜

TA贡献1895条经验 获得超7个赞

您的NPE示例与此代码等效,这要归功于自动装箱:


if ( i.intValue( ) == 0 )


因此,如果NPE i为null。

查看完整回答
1 反对 回复 2019-10-10
?
跃然一笑

TA贡献1826条经验 获得超6个赞

简短答案

关键是:


== 两个参考类型之间总是参考比较

通常,例如,使用Integer和String,您可以equals改用

== 引用类型和数字原始类型之间的始终是数字比较

引用类型将进行拆箱转换

拆箱null总是抛出NullPointerException

尽管Java对Java有很多特殊处理String,但实际上它不是原始类型

上面的语句适用于任何给定的有效 Java代码。有了这种理解,您呈现的代码段中就不会出现任何不一致之处。


长答案

以下是相关的JLS部分:


JLS 15.21.3参考相等运算符==和!=

如果相等运算符的操作数均为引用类型或null类型,则该操作为对象相等。


这解释了以下内容:


Integer i = null;

String str = null;


if (i == null) {   // Nothing happens

}

if (str == null) { // Nothing happens

}

if (str == "0") {  // Nothing happens

}

这两个操作数都是引用类型,这就是为什么==引用相等比较。


这也解释了以下内容:


System.out.println(new Integer(0) == new Integer(0)); // "false"

System.out.println("X" == "x".toUpperCase()); // "false"

为了==达到数值相等,至少一个操作数必须是数值类型:


JLS 15.21.1数值相等算子==和!=

如果相等运算符的操作数是两个数字类型的,或一个是数字类型的,并且另一种是可转换到数字类型,二进制数值提升时对操作数执行。如果操作数的提升类型为int或long,则执行整数相等性测试;否则,执行整数相等性测试。如果提升的类型为float ordouble`,则执行浮点相等性测试。


请注意,二进制数值升级执行值集转换和装箱转换。


这说明:


Integer i = null;


if (i == 0) {  //NullPointerException

}

这是摘自Effective Java 2nd Edition,第49条:首选基元而不是盒装基元:


总之,只要有选择,就优先于框式基元使用基元。基本类型更简单,更快速。如果必须使用盒装原语,请当心!自动装箱减少了使用装箱原语的冗长程度,但没有危险。当您的程序将两个装箱的原语与==运算符进行比较时,它将进行身份比较,这几乎肯定不是您想要的。当您的程序进行涉及装箱和拆箱原语的混合类型计算时,它会进行拆箱,而当您的程序进行拆箱时,它可能会抛出NullPointerException。最后,当您的程序将原始值装箱时,可能会导致创建昂贵且不必要的对象。


在某些地方您别无选择,只能使用盒装基元,例如泛型,但是否则您应该认真考虑使用盒装基元的决定是否合理。


查看完整回答
反对 回复 2019-10-10
?
BIG阳

TA贡献1859条经验 获得超6个赞

Java的开发者可以将==运算符定义为直接对不同类型的操作数进行操作,在这种情况下,如果Integer I; int i;进行比较,则I==i;可能会问到“是否I持有Integer其值是i?的引用”这一问题,可以很容易地得到回答。即使I为null。不幸的是,Java不能直接检查不同类型的操作数是否相等。而是检查该语言是否允许将一个操作数的类型转换为另一个操作数的类型,如果允许,则将转换后的操作数与未转换的操作数进行比较。这种行为意味着变量xy以及z与一些类型的组合,它可能有x==yy==z,但x!=z[例如,x = 16777216f y = 16777216 z = 16777217]。这也意味着将比较I==i翻译为“将I转换为int,如果没有抛出异常,则将其与进行比较i”。


查看完整回答
反对 回复 2019-10-10
  • 3 回答
  • 0 关注
  • 1444 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信