Scala 中的 ==
和 .equals()
有什么区别,什么时候使用?
实现与Java中的相同吗?
编辑:相关问题讨论了 AnyVal
的具体案例。更一般的情况是Any
。
您通常使用 ==
,它会路由到 equals
,但它会正确处理 null
。引用相等(很少使用)是 eq
。
TL;博士
覆盖 equals 方法来比较每个实例的内容。这与 Java 中使用的 equals 方法相同
使用 == 操作符进行比较,不用担心空引用
使用 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)
方法比较仅 引用,即实例在内存中的位置。此方法没有隐式装箱。
例子
等于 2 将返回 false,因为它重定向到 Integer.equals(...)
1 == 2 将返回 false,因为它重定向到 Integer.equals(...)
1 eq 2 不会编译,因为它要求两个参数都是 AnyRef 类型
new ArrayList() 等于 new ArrayList() 将返回 true,因为它会检查内容
new ArrayList() == new ArrayList() 将返回 true,因为它重定向到 equals(...)
new ArrayList() eq new ArrayList() 将返回 false,因为两个参数都是不同的实例
foo 等于 foo 将返回 true,除非 foo 为 null,否则将抛出 NullPointerException
foo == foo 将返回 true,即使 foo 为 null
foo eq foo 将返回 true,因为两个参数都链接到同一个引用
==
是 final 方法,并调用 .equals
,它不是 final。
这与 Java 完全不同,其中 ==
是一个运算符而不是一个方法,并且严格比较对象的引用相等性。
对于 Float
和 Double
类型,==
和 equals
之间存在一个有趣的区别:它们对待 NaN
的方式不同:
scala> Double.NaN == Double.NaN
res3: Boolean = false
scala> Double.NaN equals Double.NaN
res4: Boolean = true
编辑:正如评论中指出的那样——“这也发生在 Java 中”——取决于这到底是什么:
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
中,并根据需要转换为原始 double 和盒装 Double。因此,scala ==
显然可以归结为原始 NaN
值的比较,但 equals
使用在盒装 Double 值上定义的值(有很多隐式转换魔法正在进行,并且有一些东西被 { 5})。
如果您确实需要确定某些内容是否真的是 NaN
,请使用 isNaN
:
Java:https://docs.oracle.com/javase/7/docs/api/java/lang/Double.html#isNaN(double)
斯卡拉:http://www.scala-lang.org/files/archive/api/2.11.8/index.html#scala.Double@isNaN():Boolean
在 Scala == 首先检查 Null 值,然后在第一个对象上调用 equals 方法
3 == BigInt(3)
和BigInt(3) == 3
都是真的。但是,3.equals(BigInt(3))
为假,而BigInt(3).equals(3)
为真。因此,更喜欢使用==
。避免在 Scala 中使用equals()
。我认为==
可以很好地进行隐式转换,但equals()
不行。new java.lang.Integer(1) == new java.lang.Double(1.0)
为真而new java.lang.Integer(1) equals new java.lang.Double(1.0)
为假呢?