Scala 中 = = 和. equals 的区别是什么?

Scala 中 ==.equals()的区别是什么? 什么时候使用哪一个?

实现是否与 Java 相同?

编辑: 相关问题讨论的是 AnyVal的具体病例。较一般的病例是 Any

70234 次浏览

你通常使用 ==,它路由到 equals,除了它正确对待 null。引用相等(很少使用)是 eq

==是 final 方法,它调用 .equals,这不是 final 方法。

这与 Java 截然不同,在 Java 中,==是一个运算符而不是一个方法,并严格比较对象的引用相等性。

对于 FloatDouble类型,==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 值上定义的值(有很多隐式的转换魔术在进行,还有一些东西被 RichDouble加到 Double 上)。

如果你真的需要找出某样东西是否实际上是 NaN,使用 isNaN:

DR

  • 重写 equals方法以比较每个实例的内容
  • 使用 ==操作符进行比较,而不用担心 null引用
  • 使用 eq方法检查两个参数是否是相同的引用。建议不要使用,除非你了解这是如何工作的,通常 equals将工作,而不是你需要什么。并且确保只使用 AnyRef参数,而不仅仅使用 Any

注意: 在 equals的情况下,就像在 Java 中一样,如果你切换参数,它可能不会返回相同的结果,例如 1.equals(BigInt(1))将返回 false,反过来返回 true。这是因为每个实现只检查特定的类型。基元数字不检查第二个参数是否为 NumberBigInt类型,但只检查其他基元类型

细节

AnyRef.equals(Any)方法是被子类重写的方法。一个来自 Java 规范的方法也已经转移到了 Scala。如果在未装箱的实例上使用,它会被装箱调用(虽然隐藏在 Scala 中; 在 Java 中使用 int-> Integer时更明显)。默认实现只是比较引用(如 Java)

Any.==(Any)方法比较两个对象,并允许任一参数为 null (就像调用具有两个实例的静态方法一样)。如果两者都是 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,除非 foonull,否则将抛出 NullPointerException
  • 即使 foonullfoo == foo也会返回 true
  • foo eq foo将返回 true,因为两个参数链接到同一个引用

在 Scala ==中,首先检查 无效值,然后对第一个对象调用 等于方法