web-dev-qa-db-ja.com

Scalaの==と.equalsの違いは何ですか?

Scalaの_==_と.equals()の違いは何ですか?また、どちらを使用するのですか?

実装はJavaと同じですか?

編集:関連する質問では、AnyValの特定のケースについて説明しています。より一般的なケースはAnyです。

133
Jus12

通常は==を使用しますが、equalssを適切に処理することを除いて、nullにルーティングします。参照の平等(めったに使用されない)はeqです。

184
Didier Dupont

==はfinalメソッドであり、.equalsを呼び出しますが、これはfinalではありません。

これは、==がメソッドではなく演算子であり、オブジェクトの参照の等価性を厳密に比較するJavaとは根本的に異なります。

33
Don Roby

TL; DR

  • equalsメソッドをオーバーライドして、各インスタンスのコンテンツを比較します。これは、Javaで使用されるequalsメソッドと同じです
  • _==_演算子を使用して、null参照を気にせずに比較します
  • eqメソッドを使用して、両方の引数が[〜#〜] exactly [〜#〜]同じ参照であるかどうかを確認します。これがどのように機能するか理解していない限り使用しないことをお勧めします。多くの場合、代わりにequalsが必要なものに対して機能します。そして、これをAnyRefだけでなくAny引数でのみ使用するようにしてください

注:equalsの場合、Javaの場合と同様に、引数を切り替えると同じ結果が返されない場合があります。たとえば、1.equals(BigInt(1))falseを返します。 trueを返します。これは、各実装が特定のタイプのみをチェックするためです。プリミティブ番号は、2番目の引数がNumber型でもBigInt型でもないが、他のプリミティブ型のみであるかどうかをチェックしません

詳細

AnyRef.equals(Any)メソッドは、サブクラスによってオーバーライドされます。 Java仕様からのメソッドで、Scalaにも渡されています。ボックス化されていないインスタンスで使用する場合、これを呼び出すためにボックス化されます(Scalaでは隠されていますが、Javaではint-> Integerでより明確です)。デフォルトの実装は、参照を比較するだけです(Javaのように)

Any.==(Any)メソッドは、2つのオブジェクトを比較し、いずれかの引数をnullにすることができます(2つのインスタンスで静的メソッドを呼び出すように)。両方がnullかどうかを比較し、ボックス化されたインスタンスでequals(Any)メソッドを呼び出します。

AnyRef.eq(AnyRef)メソッドはonly参照、つまりインスタンスがメモリ内にある場所を比較します。このメソッドには暗黙的なボクシングはありません。

  • _1 equals 2_はInteger.equals(...)にリダイレクトするため、falseを返します
  • _1 == 2_はInteger.equals(...)にリダイレクトするため、falseを返します
  • _1 eq 2_は、両方の引数がAnyRef型である必要があるため、コンパイルされません
  • new ArrayList() equals new ArrayList()はコンテンツをチェックするため、trueを返します
  • new ArrayList() == new ArrayList()は、equals(...)にリダイレクトされるため、trueを返します。
  • new ArrayList() eq new ArrayList()は、両方の引数が異なるインスタンスであるため、falseを返します
  • _foo equals foo_は、truefooでない限り、nullを返し、NullPointerExceptionをスローします。
  • _foo == foo_は、truefooであっても、nullを返します
  • _foo eq foo_はtrueを返します。両方の引数が同じ参照にリンクしているためです
26
zjohn4

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浮動小数点数が定義する方法であり、すべてのプログラミング言語で実際に発生するためです(ただし、アイデンティティの概念が混乱します)。

ボックス化されたNaNは、オブジェクト参照を比較しているので、Java)の==を使用した比較に対してtrueを返します。

equalsの場合の説明はありませんが、私見では、ボックス化されていないdouble値で==と同じように動作するはずですが、そうではありません。

Scalaに変換すると、問題はScalaがプリミティブ型とオブジェクト型をAnyに統一し、プリミティブdoubleとしたがって、scala ==は、明らかにNaN値の比較に要約されますが、equalsはboxed Double値で定義されたものを使用します(多くの暗黙的な変換マジックが進行しており、RichDoubleによってdoubleに変換されたものがあります)。

実際に何かがNaNであるかどうかを調べる必要がある場合は、isNaNを使用します。

5
scravy

In Scala ==最初にNull値をチェックしてから、最初のオブジェクトでequalsメソッドを呼び出します

1
jack