Scala中==和.equals有什么区别?


144

==.equals()Scala 之间有什么区别,什么时候使用?

实现与Java中的一样吗?

编辑:相关问题谈论的特定情况AnyVal。更一般的情况是Any



@Ben我认为考虑到询问日期,其他问题应标记为重复。另外,我觉得这两个问题是不同的。
2016年

Answers:


201

您通常使用==,它会路由到equals,但会null正确处理。引用等式(很少使用)为eq


12
使用Java库时也适用吗?
2011年

20
是的 例如,新的java.util.ArrayList [Int]()==新的java.util.ArrayList [Int](),因为ArrayList上的等号是内容相等。
Didier Dupont

5
在Int和Long和==与.equals()之间也存在一些奇怪的行为。与Int和Long相同的数字对==返回true,对等于返回false。因此,==并不总是等于路由。
Harold L

24
更有趣的是,Both 3 == BigInt(3)BigInt(3) == 3都是真实的。但是,3.equals(BigInt(3))是错误的,而是BigInt(3).equals(3)真实的。因此,更喜欢使用==。避免equals()在Scala中使用。我认为==隐式转换效果很好,但equals()事实并非如此。
Naetmul

那么为什么new java.lang.Integer(1) == new java.lang.Double(1.0)是真的却new java.lang.Integer(1) equals new java.lang.Double(1.0)是假的呢?
Eastsun'9

33

==是final方法,并调用.equals,而不是final方法。

这与Java根本不同,Java ==是Java 的运算符,而不是方法,并且严格比较对象的引用相等性。


29

TL; DR

  • 覆盖equals方法,用于比较每个实例的内容。这与equalsJava中使用的方法相同
  • 使用==运算符进行比较,而不必担心null引用
  • 使用eq的方法来检查,如果两个参数是EXACTLY相同的参考。建议不要使用,除非您了解它的工作原理,并且通常equals会根据您的需要工作。并确保仅将此AnyRef参数与参数一起使用,而不仅仅是Any

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

细节

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
  • foo == foo将返回true,即使foonull
  • foo eq foo将返回true,因为两个参数都链接到相同的引用

6

有之间的有趣的差异==,并equalsFloatDouble类型:他们对待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浮点数定义它的方式,并且确实应该在每种编程语言中发生(尽管它在某种程度上与身份的概念混淆了)。

==当我们在比较对象引用时,带框的NaN对于在Java中使用的比较而言,它的结果为true 。

对于这种equals情况,我没有任何解释,恕我直言,它的行为应与未==装箱的double值相同,但事实并非如此。

转换为Scala后,问题变得更加复杂了,因为Scala将原始类型和对象类型统一Any为所需的类型,并转换为原始double和盒装Double。因此,scala ==显然可以归结为原始NaN值的比较,但是equals使用了在装箱的Double值上定义的值(存在很多隐式转换魔术,并且有很多东西被放大为double RichDouble)。

如果您真的需要找出是否确实NaN有用,请使用isNaN


这也发生在Java中!
伊万·萨特里亚

4

在Scala ==中,首先检查Null值,然后在第一个对象上调用equals方法

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.