java - 为什么在 Java 中比较 Integer 和 int 会抛出 NullPointerException?

标签 java nullpointerexception boxing

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

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 尝试从 null 中提取 int 值)并且比较操作的优先级较低,这就是引发异常的原因。

问题是:为什么在Java中以这种方式实现?为什么拳击比比较引用具有更高的优先级?或者为什么他们没有在装箱前对 null 实现验证?

目前,当 NullPointerException 与包装原语一起抛出而不是与 true 对象类型一起抛出时,它看起来不一致。

最佳答案

简短的回答

关键点是这样的:

  • == 两个引用类型之间总是引用比较
    • 通常情况下,例如对于 IntegerString,你会想使用 equals 来代替
  • == 在引用类型和数字原始类型之间始终是数字比较
    • 引用类型会进行拆箱转换
    • 拆箱 null 总是抛出 NullPointerException
  • 虽然 Java 对 String 有很多特殊处理,但它实际上并不是原始类型

上述语句适用于任何给定的有效 Java 代码。有了这种理解,您提供的代码段中就没有任何不一致之处。


长答案

以下是相关的 JLS 部分:

JLS 15.21.3 Reference Equality Operators == and !=

If the operands of an equality operator are both of either reference type or the null type, then the operation is object equality.

这解释了以下内容:

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 Numerical Equality Operators == and !=

If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible to numeric type, binary numeric promotion is performed on the operands. If the promoted type of the operands is int or long, then an integer equality test is performed; if the promoted type is float or double`, then a floating-point equality test is performed.

Note that binary numeric promotion performs value set conversion and unboxing conversion.

这说明:

Integer i = null;

if (i == 0) {  //NullPointerException
}

这是Effective Java 2nd Edition, Item 49: Prefer primitives to boxed primitives的节选:

In summary, use primitives in preference to boxed primitive whenever you have the choice. Primitive types are simpler and faster. If you must use boxed primitives, be careful! Autoboxing reduces the verbosity, but not the danger, of using boxed primitives. When your program compares two boxed primitives with the == operator, it does an identity comparison, which is almost certainly not what you want. When your program does mixed-type computations involving boxed and unboxed primitives, it does unboxing, and when your program does unboxing, it can throw NullPointerException. Finally, when your program boxes primitive values, it can result in costly and unnecessary object creations.

有些地方你别无选择,只能使用盒装图元,例如泛型,否则您应该认真考虑使用盒装原语的决定是否合理。

引用文献

相关问题

相关问题

关于java - 为什么在 Java 中比较 Integer 和 int 会抛出 NullPointerException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3352791/

相关文章:

java - 读取 BufferedReader 的内容时出现 NullPointerException,尽管它不为空

c# - 如何检测代码中的装箱/拆箱

c# - 我可以在不装箱的情况下通过反射为结构设置值吗?

java - 学习线程 - 仅在另一个方法完成后才运行一个方法

java - 什么是NullPointerException,我该如何解决?

Java:如何在不进行时区转换的情况下将日期保存到MySQL中?

java - 什么是NullPointerException,我该如何解决?

vector - 如何拆箱包含在多态向量中的元素?

java - 从 Java 程序中获取局部变量的名称和类型

java - 如何将 Map<String, List<Integer>> 从 JSON 映射到 JPA?