为什么将Integer与int进行比较可以在Java中抛出NullPointerException? [英] Why comparing Integer with int can throw NullPointerException in Java?
问题描述
观察这种情况让我非常困惑:
It was very confusing to me to observe this situation:
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
...
}
所以,as我认为首先执行装箱操作(即java尝试从 null
中提取int值),并且比较操作具有较低的优先级,这就是抛出异常的原因。
So, as I think boxing operation is executed first (i.e. java tries to extract int value from null
) and comparison operation has lower priority that's why the exception is thrown.
问题是:为什么在Java中以这种方式实现?为什么拳击优先于比较参考?或者为什么他们没有在拳击前对 null
实施验证?
The question is: why is it implemented in this way in Java? Why boxing has higher priority then comparing references? Or why didn't they implemented verification against null
before boxing?
当 NullPointerException
被包装的基元抛出时,它看起来不一致,并且不会抛出 true 对象类型。
At the moment it looks inconsistent when NullPointerException
is thrown with wrapped primitives and is not thrown with true object types.
推荐答案
简答
关键点是:
The Short Answer
The key point is this:
-
==
两种参考类型之间总是参考比较
- 通常情况下,例如使用
Integer
和String
,您要使用等于
==
between two reference types is always reference comparison- More often than not, e.g. with
Integer
andString
, you'd want to useequals
instead
- 引用类型将进行拆箱转换
- 拆箱
null
总是抛出NullPointerException
- The reference type will be subjected to unboxing conversion
- Unboxing
null
always throwsNullPointerException
以上语句适用于任何给定的有效 Java代码。根据这种理解,您提供的代码段中没有任何不一致。
The above statements hold for any given valid Java code. With this understanding, there is no inconsistency whatsoever in the snippet you presented.
以下是相关的JLS部分:
Here are the relevant JLS sections:
JLS 15.21.3参考等式运算符
==
和!=
如果等于运算符的操作数都是引用类型或 null 类型,然后操作是对象相等。
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 }
两个操作数是引用类型,这就是
==
是引用相等比较的原因。Both operands are reference types, and that's why the
==
is reference equality comparison.这也解释了以下内容: / p>
This also explains the following:
System.out.println(new Integer(0) == new Integer(0)); // "false" System.out.println("X" == "x".toUpperCase()); // "false"
对于
==
为了数字相等,至少有一个操作数必须是数字类型:
JLS 15.21.1数值等式运算符
==
和!=
如果等于运算符的操作数是两者的数字类型,或一个的数字类型和另一个是可转换的到数字类型,对操作数执行二进制数字提升。如果提升类型的操作数是
int
或long
,则执行整数相等测试;如果提升类型是float或
double`,则执行浮点相等测试。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,第49项:首选原语为盒装基元:
总之,只要您有选择,就可以优先使用原始元素。原始类型更简单,更快捷。如果你必须使用盒装基元,小心!自动装箱减少了使用盒装基元的冗长度,但没有降低危险性。当您的程序将两个盒装基元与
==
运算符进行比较时,它会进行身份比较,这几乎肯定不是您想要的。当你的程序执行涉及盒装和未装箱原语的混合类型计算时,它会进行拆箱,当你的程序进行拆箱时,它会抛出NullPointerException
。最后,当你的程序框原始值时,它可能导致昂贵和不必要的对象创建。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.有些地方你别无选择但要使用盒装基元,例如泛型,但你应该认真考虑是否有合理使用盒装基元的决定。
There are places where you have no choice but to use boxed primitives, e.g. generics, but otherwise you should seriously consider if a decision to use boxed primitives is justified.
- JLS 4.2。原始类型和值
- 数字类型是整数类型和浮点类型。
- JLS 4.2. Primitive Types and Values
- "The numeric types are the integral types and the floating-point types."
- 一种类型据说是可兑换到数字类型如果是数字类型,或者它是可以通过取消装箱转换转换为数字类型的引用类型。
- 取消装箱转换会转换[ ...]从类型
整数
到键入int
- 如果
r
是null
,取消装箱转换会抛出NullPointerException
- "A type is said to be convertible to a numeric type if it is a numeric type, or it is a reference type that may be converted to a numeric type by unboxing conversion."
- "Unboxing conversion converts [...] from type
Integer
to typeint
" - "If
r
isnull
, unboxing conversion throws aNullPointerException
"
- 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 / C#中的int和Integer有什么区别?
- 是否保证新的Integer(i)== i in Java?(是的!这个盒子是未装箱的,而不是其他方式!)
- 为什么
int num = Integer.getInteger(123)
throwNullPointerException
?(!!!) - Java noob:仅针对对象的泛型?(不幸的是,是的)
- Java
String.equals
对比==
- What is the difference between an int and an Integer in Java/C#?
- Is it guaranteed that new Integer(i) == i in Java? (YES!!! The box is unboxed, not other way around!)
- Why does
int num = Integer.getInteger("123")
throwNullPointerException
? (!!!) - Java noob: generics over objects only? (yes, unfortunately)
- Java
String.equals
versus==
这篇关于为什么将Integer与int进行比较可以在Java中抛出NullPointerException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- More often than not, e.g. with
- 通常情况下,例如使用