观察到这种情况让我非常困惑:
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 对象类型一起抛出时,它看起来不一致。
最佳答案
简短的回答
关键点是这样的:
==
两个引用类型之间总是引用比较- 通常情况下,例如对于
Integer
和String
,你会想使用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
orlong
, then an integer equality test is performed; if the promoted type isfloat 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 throwNullPointerException
. Finally, when your program boxes primitive values, it can result in costly and unnecessary object creations.
有些地方你别无选择,只能使用盒装图元,例如泛型,否则您应该认真考虑使用盒装原语的决定是否合理。
引用文献
- JLS 4.2. Primitive Types and Values
- “数值类型是整数类型和浮点类型。”
- JLS 5.1.8 Unboxing Conversion
- “如果一个类型是数值类型,或者是可以通过拆箱转换转换为数值类型的引用类型,则称该类型可转换为数值类型。”
- “拆箱转换将 [...] 从类型
Integer
转换为类型int
” - "如果
r
为null
,拆箱转换会抛出NullPointerException
"
- Java Language Guide/Autoboxing
- JLS 15.21.1 Numerical Equality Operators
==
and!=
- JLS 15.21.3 Reference Equality Operators
==
and!=
- JLS 5.6.2 Binary Numeric Promotion
相关问题
- When comparing two
Integers
in Java does auto-unboxing occur? - Why are these
==
but notequals()
? - Java: What’s the difference between autoboxing and casting?
相关问题
关于java - 为什么在 Java 中比较 Integer 和 int 会抛出 NullPointerException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3352791/