Java的等号运算符是否满足交换律?

7

考虑以下Java代码:

Integer foo = bar();
if(foo == 5) ...;
if(5 == foo) ...;

这些比较是否相等 -- 特别是在foo可能为null的情况下?它们会展开成foo.getValue() == 55 == foo.getValue(),还是更类似于 foo.equals(new Integer(5))new Integer(5).equals(foo),或者其他什么?一种或两种或都没有会抛出 NPE 吗?


1
看起来你在问它是否对称,而不是交换律。当涉及到什么会抛出NPE时,通常的规则适用(尽管值得一提的是,我相信大多数实现如果参数为null,则返回false)。 - Dennis Meng
@user2864740:问题不同,因为我也在问操作数的顺序是否重要。 - Dolda2000
@user2864740:啊,我明白了;对不起。我以为你只是在指出一个重复的问题。 - Dolda2000
@Dolda2000,是的,你记错了。x*x成立会使它自反 - Dennis Meng
1
啊等等,对了。我猜我需要更多的咖啡因。 :) - Dennis Meng
显示剩余5条评论
3个回答

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. 二进制数字提升

当运算符将二进制数字提升应用于一对操作数时,每个操作数都必须表示可转换为数字类型的值,则按照以下顺序应用以下规则:

如果任何操作数是引用类型,则对其进行拆箱转换(§5.1.8)。

这意味着 if(foo == 5) ...;if(foo.intValue() == 5) ...; 是相同的,if(5 == foo) 意味着 if (5 == foo.intValue())。如果 foo 等于 null,则两种情况都会导致 NPE。

1
谢谢!规范中的引用非常清楚地说明了正在发生的事情。 - Dolda2000
值得注意的是,由于整数是final的,您无法像覆盖intValue()为状态式等疯狂的事情。 :) - Rag

1

==对称的;也就是说,对于任何值xy(x == y) == (y == x)。这是JLS §15.21.1针对数字提供给我们的保证,以及§15.21.3针对引用类型(或任何非原始值)。

它也可以被视为传递的,也就是说,如果存在三个值x,y,z,并且x == y && y == z,那么x == z。这同样由相同的JLS规范提供 - 仅重复以减轻常见变量y的问题。

问题在于自动装箱;当你试图拆箱null时,根据JLS,你将得到一个NullPointerException,与你接下来要进行的比较操作无关。
实际上:
  • 在比较的一侧是一个包装的基本类型,而在另一侧是原始类型。任何一个值都还没有被考虑。

  • 鉴于这是一个包装的基本类型,会强制进行数字比较,因此Java会尝试取消装箱。

  • null无法取消装箱,因此出现了NullPointerException

这就是equals()的作用 - 根据其约定,如果两个非空实例确实是同一物体,则它们必须相互等同。 如果这些值中的任何一个(但不是两个)为null,则它们不是相同的实例。
我说“有点像”是因为实际上没有强制执行Object#equals上的所谓约定; 你可以(通过一些努力)编写一个不对称的equals()方法,尽管人们会想知道为什么你要这样做。

那第二个属性是传递性,而不是交换性。 - Chris Hayes
实际上,“对称”是用于二元关系的术语,而“可交换”是用于二元运算的术语。==当然可以被视为任一种,但在这种情况下,我主要将其视为一种操作(考虑到我主要关注其副作用而不是作为关系)。 - Dolda2000
@Dolda2000:副作用?什么副作用?JLS所概述的只是它的行为,每次都是如此——我无法想象“==”对其接收的操作数有任何副作用。 - Makoto
@Makoto:它具有潜在抛出异常的副作用,这对于关系来说是不可定义的。 - Dolda2000
但是,对null的拆箱是==语法的隐含部分。而且,“副作用”这个术语并不一定只带有与函数式编程语言相关的含义。在这种情况下,我使用它来表示除了简单地进行布尔比较之外的其他影响。 - Dolda2000
显示剩余3条评论

0

1) 1和2之间没有区别。

2) 编译器将foo == 5转换为foo.intValue() == 5(装箱)。

3) 如果foonull,则会在运行时抛出NPE。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接