Was ist der Unterschied zwischen ==
und .equals()
in Scala und wann welche zu verwenden?
Ist die Implementierung dieselbe wie in Java?
EDIT: Die verwandte Frage spricht über bestimmte Fälle von AnyVal
. Der allgemeinere Fall ist Any
.
Was ist der Unterschied zwischen ==
und .equals()
in Scala und wann welche zu verwenden?
Ist die Implementierung dieselbe wie in Java?
EDIT: Die verwandte Frage spricht über bestimmte Fälle von AnyVal
. Der allgemeinere Fall ist Any
.
Antworten:
Normalerweise verwendet ==
es Routen zu equals
, außer dass es null
s richtig behandelt . Referenzgleichheit (selten verwendet) ist eq
.
3 == BigInt(3)
und BigInt(3) == 3
wahr sind. Aber 3.equals(BigInt(3))
ist falsch, während BigInt(3).equals(3)
es wahr ist. Verwenden Sie daher lieber ==
. Vermeiden Sie die Verwendung equals()
in Scala. Ich denke ==
, implizite Konvertierung ist gut, aber equals()
nicht.
new java.lang.Integer(1) == new java.lang.Double(1.0)
ist wahr, während new java.lang.Integer(1) equals new java.lang.Double(1.0)
falsch ist?
equals
Methode überschreiben , um den Inhalt jeder Instanz zu vergleichen. Dies ist die gleiche equals
Methode wie in Java==
Operator zum Vergleichen, ohne sich um null
Referenzen kümmern zu müsseneq
Methode, um zu überprüfen, ob beide Argumente genau dieselbe Referenz sind. Empfohlen, nicht zu verwenden, es sei denn, Sie verstehen, wie dies funktioniert, und funktionieren häufig equals
für das, was Sie stattdessen benötigen. Und stellen Sie sicher, dass Sie dies nur mit AnyRef
Argumenten verwenden, nicht nurAny
HINWEIS: Im Fall von equals
, wie in Java, wird möglicherweise nicht das gleiche Ergebnis zurückgegeben, wenn Sie die Argumente wechseln, z. B. 1.equals(BigInt(1))
wird dort zurückgegeben, false
wo die Umkehrung zurückgegeben wird true
. Dies liegt daran, dass jede Implementierung nur bestimmte Typen überprüft. Primitive Zahlen prüfen nicht, ob das zweite Argument Number
noch vom BigInt
Typ ist, sondern nur von anderen primitiven Typen
Die AnyRef.equals(Any)
Methode wird von Unterklassen überschrieben. Eine Methode aus der Java-Spezifikation, die auch für Scala verfügbar ist. Wenn es für eine Instanz ohne Box verwendet wird, wird es als Box aufgerufen, um dies aufzurufen (obwohl in Scala versteckt; in Java mit int
-> offensichtlicher Integer
). Die Standardimplementierung vergleicht lediglich Referenzen (wie in Java).
Die Any.==(Any)
Methode vergleicht zwei Objekte und lässt zu, dass jedes Argument null ist (als würde eine statische Methode mit zwei Instanzen aufgerufen). Es vergleicht, wenn beide sind null
, und ruft die equals(Any)
Methode für eine Box-Instanz auf.
Die AnyRef.eq(AnyRef)
Methode vergleicht nur Referenzen, dh dort befindet sich die Instanz im Speicher. Für diese Methode gibt es kein implizites Boxen.
1 equals 2
wird zurückkehren false
, wenn es umleitetInteger.equals(...)
1 == 2
wird zurückkehren false
, wenn es umleitetInteger.equals(...)
1 eq 2
wird nicht kompiliert, da beide Argumente vom Typ sein müssen AnyRef
new ArrayList() equals new ArrayList()
wird zurückkehren true
, wenn es den Inhalt überprüftnew ArrayList() == new ArrayList()
wird zurückkehren true
, wenn es umleitetequals(...)
new ArrayList() eq new ArrayList()
wird zurückgegeben false
, da beide Argumente unterschiedliche Instanzen sindfoo equals foo
wird zurückkehren true
, es foo
sei denn, ist null
, dann wird ein werfenNullPointerException
foo == foo
wird zurückkehren true
, auch wenn foo
istnull
foo eq foo
wird zurückgegeben true
, da beide Argumente auf dieselbe Referenz verweisenEs gibt einen interessanten Unterschied zwischen ==
und equals
für Float
und Double
Typen: Sie behandeln NaN
unterschiedlich:
scala> Double.NaN == Double.NaN
res3: Boolean = false
scala> Double.NaN equals Double.NaN
res4: Boolean = true
Bearbeiten: Wie in einem Kommentar erwähnt - "das passiert auch in Java" - hängt davon ab, was genau das ist:
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));
}
Dies wird gedruckt
false
true
true
Die unboxedNan
Ausbeuten werden also false
im Vergleich zur Gleichheit verglichen, da IEEE-Gleitkommazahlen dies so definieren und dies wirklich in jeder Programmiersprache geschehen sollte (obwohl dies irgendwie mit dem Begriff der Identität zu tun hat).
Das Boxed NaN ergibt true für den Vergleich mit ==
Java, wenn wir Objektreferenzen vergleichen.
Ich habe keine Erklärung für den equals
Fall, IMHO sollte es sich wirklich genauso verhalten wie ==
bei Doppelwerten ohne Box, aber das tut es nicht.
In Scala übersetzt ist die Angelegenheit etwas komplizierter, da Scala die primitiven und Objekttypen vereinheitlicht und je Any
nach Bedarf in das primitive Double und das Boxed Double übersetzt hat. Daher läuft die Scala ==
anscheinend auf einen Vergleich primitiver NaN
Werte hinaus, equals
verwendet jedoch diejenige, die für Boxed-Double-Werte definiert ist (es gibt eine Menge impliziter Konvertierungsmagie und es gibt Dinge, die auf Double-Werte gepimpt werden RichDouble
).
Wenn Sie wirklich herausfinden müssen, ob tatsächlich etwas NaN
verwendet wird isNaN
: