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

Rom*_*man 77 java boxing nullpointerexception

观察这种情况让我非常困惑:

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
   ...
}
Run Code Online (Sandbox Code Playgroud)

因此,我认为首先执行装箱操作(即java尝试从中提取int值null),并且比较操作具有较低的优先级,这就是抛出异常的原因.

问题是:为什么在Java中以这种方式实现它?为什么拳击优先于比较参考?或者为什么他们没有null在拳击前实施验证?

目前,当NullPointerException使用包装的基元抛出它时看起来不一致,并且不会抛出真正的对象类型.

pol*_*nts 135

简答

关键是这个:

  • == 两种引用类型之间始终是引用比较
    • 通常情况下,例如使用IntegerString,你想使用equals替代
  • == 引用类型和数字基元类型之间始终是数字比较
    • 引用类型将进行拆箱转换
    • 拆箱null总是抛出NullPointerException
  • 虽然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
}
Run Code Online (Sandbox Code Playgroud)

两个操作数都是引用类型,这==就是引用相等比较的原因.

这也解释了以下内容:

System.out.println(new Integer(0) == new Integer(0)); // "false"
System.out.println("X" == "x".toUpperCase()); // "false"
Run Code Online (Sandbox Code Playgroud)

为了==是数字相等,至少有一个操作数必须是数字类型:

JLS 15.21.1数值等式算子==!=

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

请注意,二进制数字促销执行值集转换和拆箱转换.

这解释了:

Integer i = null;

if (i == 0) {  //NullPointerException
}
Run Code Online (Sandbox Code Playgroud)

以下是Effective Java 2nd Edition的摘录,第49项:首选基元到盒装基元:

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

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

参考

相关问题

相关问题

  • 为什么编译器不会用`(myInteger != null && myInteger == 0)` 替换表达式`(myInteger == 0)` 而不是依靠开发人员编写这个样板空检查代码?IMO 我应该能够检查“if (myBoolean)”,并且当且仅当基础值特别是“true”时,它才应该评估为“true”——我不应该首先进行空检查。 (3认同)
  • 至于*为什么*`someRef == 0`总是数字比较,这是一个非常合理的选择,因为比较两个盒装基元的引用几乎*总是*程序员错误.在这种情况下默认参考比较是没用的. (2认同)

Ale*_*yak 14

由于自动装箱,您的NPE示例等同于此代码:

if ( i.intValue( ) == 0 )

因此NPE inull.


归档时间:

查看次数:

33062 次

最近记录:

11 年,9 月 前