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 nulls richtig behandelt . Referenzgleichheit (selten verwendet) ist eq.
3 == BigInt(3)und BigInt(3) == 3wahr 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?
equalsMethode überschreiben , um den Inhalt jeder Instanz zu vergleichen. Dies ist die gleiche equalsMethode wie in Java==Operator zum Vergleichen, ohne sich um nullReferenzen kümmern zu müsseneqMethode, 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 equalsfür das, was Sie stattdessen benötigen. Und stellen Sie sicher, dass Sie dies nur mit AnyRefArgumenten verwenden, nicht nurAnyHINWEIS: 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, falsewo 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 Numbernoch vom BigIntTyp 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 2wird zurückkehren false, wenn es umleitetInteger.equals(...)1 == 2wird zurückkehren false, wenn es umleitetInteger.equals(...)1 eq 2 wird nicht kompiliert, da beide Argumente vom Typ sein müssen AnyRefnew 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 foowird zurückkehren true, es foosei denn, ist null, dann wird ein werfenNullPointerExceptionfoo == foowird zurückkehren true, auch wenn fooistnullfoo eq foowird zurückgegeben true, da beide Argumente auf dieselbe Referenz verweisenEs gibt einen interessanten Unterschied zwischen ==und equalsfür Floatund DoubleTypen: Sie behandeln NaNunterschiedlich:
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 unboxedNanAusbeuten werden also falseim 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 equalsFall, 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 Anynach Bedarf in das primitive Double und das Boxed Double übersetzt hat. Daher läuft die Scala ==anscheinend auf einen Vergleich primitiver NaNWerte hinaus, equalsverwendet 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 NaNverwendet wird isNaN: