Scala 中
==
和 .equals()
有什么区别,何时使用哪个?
实现和Java一样吗?
有一个类似的问题(为什么 == 运算符和 equals() 对于 Scala 中的 AnyVal 值的行为不同),但这是特定于
AnyVal
的。 这个问题涉及更一般的情况 Any
。
您通常使用
==
,它会路由到 equals
,但它会正确处理 null
。引用相等(很少使用)是eq
。
equals
方法来比较每个实例的内容。这与 Java 中使用的equals
方法相同==
运算符进行比较,无需担心null
引用eq
方法检查两个参数是否完全相同的引用。建议不要使用,除非您了解其工作原理,并且通常 equals
可以满足您的需要。并且确保仅将其与 AnyRef
参数一起使用,而不仅仅是 Any
注意:对于
equals
的情况,就像在 Java 中一样,如果切换参数,它可能不会返回相同的结果,例如 1.equals(BigInt(1))
将返回 false
,而反函数将返回 true
。这是因为每个实现仅检查特定类型。原始数字不检查第二个参数是否属于 Number
或 BigInt
类型,而仅检查其他原始类型
AnyRef.equals(Any)
方法是被子类重写的方法。 Java 规范中的方法也已转移到 Scala 中。如果在未装箱的实例上使用,它会被装箱来调用它(尽管在 Scala 中隐藏;在 Java 中更明显,带有 int
->Integer
)。默认实现仅比较引用(如 Java 中)
Any.==(Any)
方法比较两个对象并允许任一参数为空(就像调用具有两个实例的静态方法一样)。它比较两者是否都是 null
,然后调用装箱实例上的 equals(Any)
方法。
AnyRef.eq(AnyRef)
方法仅比较引用,即实例在内存中的位置。此方法没有隐式装箱。
示例
1 equals 2
false
,因为它重定向到 Integer.equals(...)
1 == 2
false
,因为它重定向到 Integer.equals(...)
1 eq 2
AnyRef
类型
new ArrayList() equals new ArrayList()
true
,因为它检查内容new ArrayList() == new ArrayList()
true
,因为它重定向到 equals(...)
new ArrayList() eq new ArrayList()
false
,因为两个参数都是不同的实例foo equals foo
true
,除非 foo
是 null
,然后会抛出 NullPointerException
foo == foo
true
,即使 foo
是 null
foo eq foo
true
,因为两个参数都链接到相同的引用
==
是最终方法,并调用
.equals
,这不是最终方法。这与 Java 完全不同,其中
==
是一个运算符而不是方法,并且严格比较对象的引用相等性。
==
和
equals
类型,Float
和 Double
之间有一个有趣的区别:它们对待 NaN
的方式不同:scala> Double.NaN == Double.NaN
res3: Boolean = false
scala> Double.NaN equals Double.NaN
res4: Boolean = true
编辑: 正如评论中指出的那样 - “这也发生在 Java 中” - 取决于 this 到底是什么:
public static void main(final String... args) {
final double unboxedNaN = Double.NaN;
final Double boxedNaN = Double.valueOf(Double.NaN);
System.out.println(unboxedNaN == unboxedNaN);
System.out.println(boxedNaN == boxedNaN);
System.out.println(boxedNaN.equals(boxedNaN));
}
这将打印
false
true
true
因此,在比较相等性时,
unboxedNan
会产生
false
,因为这是 IEEE 浮点数定义它的方式,并且这应该在每种编程语言中真正发生(尽管它在某种程度上与身份概念混淆)。当我们比较对象引用时,在 Java 中使用
==
进行比较时,装箱的 NaN 会产生 true。
我没有对
equals
情况的解释,恕我直言,它确实应该与未装箱的双值上的
==
表现相同,但事实并非如此。转换为 Scala,情况会稍微复杂一些,因为 Scala 将原始类型和对象类型统一为
Any
,并根据需要转换为原始双精度型和装箱双精度型。因此,scala
==
显然可以归结为原始 NaN
值的比较,但是 equals
使用在盒装 Double 值上定义的值(存在大量隐式转换魔法,并且有一些东西通过 被添加到双精度值上) RichDouble
)。如果您确实需要找出某些东西是否确实是
NaN
,请使用
isNaN
:Java:
首先检查 Null 值,然后在第一个对象上调用 equals 方法