ChatGPT解决这个技术问题 Extra ChatGPT

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

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

实现与Java中的相同吗?

编辑:相关问题讨论了 AnyVal 的具体案例。更一般的情况是Any

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

E
Erik Kaplun

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


它在使用 Java 库时也适用吗?
确实如此。例如 new java.util.ArrayList[Int]() == new java.util.ArrayList[Int](),因为 ArrayList 上的 equals 是内容相等。
Int 和 Long 以及 == 与 .equals() 之间也存在一些奇怪的行为。与 Int 和 Long 相同的数字对于 == 返回 true,但对于 equals 返回 false。所以 == 并不总是路由到 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) 为假呢?
z
zjohn4

TL;博士

覆盖 equals 方法来比较每个实例的内容。这与 Java 中使用的 equals 方法相同

使用 == 操作符进行比较,不用担心空引用

使用 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,然后调用盒装实例的 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,因为两个参数都链接到同一个引用


您还可以在scala中解释===吗?
D
Don Roby

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

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


s
scravy

对于 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 值上定义的值(有很多隐式转换魔法正在进行,并且有一些东西被 { 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


这也发生在 Java 中!
j
jack

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