考虑以下Java代码:
Integer foo = bar();
if(foo == 5) ...;
if(5 == foo) ...;
这些比较是否相等 - 尤其是foo
null
的可能性?它们是扩展为foo.getValue() == 5
和5 == foo.getValue()
,还是更类似于foo.equals(new Integer(5))
和new Integer(5).equals(foo)
,还是其他内容?可能是其中一个或两个或两个都没有投入NPE?
答案 0 :(得分:1)
来自JLS:
15.21.1。数值等式算子==和!=
如果等于运算符的操作数都是数字类型,或者 一个是数字类型,另一个是可转换的(§5.1.8) 数字类型,对操作数执行二进制数字提升 (§5.6.2)。
5.1.8的相关规则是:
如果r是Integer类型的引用,则取消装箱转换会转换 r进入r.intValue()
5.6.2说:
5.6.2。二进制数字促销
当运算符将二进制数字提升应用于一对时 操作数,每个操作数必须表示可转换为a的值 数字类型,以下规则适用:
如果任何操作数属于引用类型,则将其取消装箱 转换(第5.1.8节)。
这意味着if(foo == 5) ...;
与if(foo.intValue() == 5) ...;
相同,if(5 == foo)
表示if (5 == foo.intValue())
。
如果foo
等于null
,则无论如何都会获得NPE。
答案 1 :(得分:1)
==
对称;也就是说,对于任何值x
和y
,(x == y) == (y == x)
。这是JLS §15.21.1为数字提供的保证,§15.21.3为参考类型(或所有非原始值)提供的保证。
它也可以被视为传递,因为如果存在三个值x, y, z
,则x == y && y == z
,然后x == z
。这再次由相同的JLS规范提供 - 仅重复以缓解公共变量y
的问题。
真正的问题来自于自动装箱;当您转到取消装箱null
,然后by the JLS时,您将获得NullPointerException
- 独立于您接下来将要执行的比较操作。
有效:
比较的一侧有一个盒装基元类型,另一侧有基元。尚未考虑其中任何一个的价值。
鉴于原始will force numerical comparison的值是由于它是一个盒装基元,Java将尝试取消装箱的值。
您无法取消装箱null
,因此NullPointerException
。
这是({3}}步入的地方 - 通过它的契约,如果它们确实是同一个东西,那么两个非空实例必须彼此相等。如果这些值中的任何一个(但不是两个)都是null
,则它们不是相同的实例。
我说“有点”,因为在Object#equals
上实际上并没有强制执行所谓的合同;你可以(通过一些努力)编写一个非对称的equals()
方法,虽然有人会想知道你为什么要这样做。
答案 2 :(得分:0)
1)1和2之间没有区别
2)编译器将foo == 5
转换为foo.intValue() == 5
(发件箱)
3)如果foo
为null
NPE在运行时被抛出