Quelle est la différence entre ==
Et .equals()
dans Scala, et quand utiliser lequel?
La mise en œuvre est-elle la même qu'en Java?
EDIT: La question connexe parle de cas spécifiques de AnyVal
. Le cas plus général est Any
.
Vous utilisez normalement ==
, il est dirigé vers equals
, sauf qu'il traite correctement null
s. L'égalité de référence (rarement utilisée) est eq
.
==
est une méthode finale et appelle .equals
, qui n'est pas définitif.
Ceci est radicalement différent de Java, où ==
est un opérateur plutôt qu'une méthode et compare strictement l'égalité de référence pour les objets.
equals
pour comparer le contenu de chaque instance. C'est la même méthode equals
que celle utilisée en Java==
Pour comparer, sans vous soucier de null
référenceseq
pour vérifier si les deux arguments sont EXACTEMENT la même référence. Recommandé de ne pas utiliser à moins que vous ne compreniez comment cela fonctionne et souvent equals
fonctionnera pour ce dont vous avez besoin à la place. Et assurez-vous de ne l'utiliser que avec AnyRef
arguments, pas seulement Any
NOTE: Dans le cas de equals
, tout comme en Java, il est possible que le résultat ne soit pas identique si vous changez les arguments, par exemple 1.equals(BigInt(1))
renverra false
où l'inverse sera retourne true
. Cela est dû au fait que chaque implémentation vérifie uniquement des types spécifiques. Les nombres primitifs ne vérifient pas si le second argument est de type Number
ni BigInt
mais uniquement d'autres types primitifs
La méthode AnyRef.equals(Any)
est celle qui est surchargée par les sous-classes. Une méthode de la Java Spécification qui est passée à Scala aussi. Si elle est utilisée sur une instance sans boîte, elle est appelée pour cela (bien que cachée dans Scala ; plus évident dans Java avec int
-> Integer
). L'implémentation par défaut compare simplement les références (comme en Java).
La méthode Any.==(Any)
compare deux objets et permet à l'un ou l'autre des arguments d'être null (comme si vous appeliez une méthode statique avec deux instances). Il compare si les deux sont null
, puis appelle la méthode equals(Any)
sur une instance encadrée.
La méthode AnyRef.eq(AnyRef)
compare niquement références, c’est-à-dire où l’instance est située en mémoire. Il n'y a pas de boxe implicite pour cette méthode.
1 equals 2
Retournera false
, car il redirige vers Integer.equals(...)
1 == 2
Retournera false
, car il redirige vers Integer.equals(...)
1 eq 2
Ne compilera pas, car les deux arguments doivent être de type AnyRef
new ArrayList() equals new ArrayList()
retournera true
, car il vérifie le contenunew ArrayList() == new ArrayList()
retournera true
, car il redirige vers equals(...)
new ArrayList() eq new ArrayList()
retournera false
, car les deux arguments sont des instances différentesfoo equals foo
Retournera true
, à moins que foo
ne soit null
, alors jettera un NullPointerException
foo == foo
Retournera true
, même si foo
est null
foo eq foo
Retournera true
, car les deux arguments sont liés à la même référenceIl y a une différence intéressante entre ==
et equals
pour Float
et Double
types: ils traitent NaN
différemment:
scala> Double.NaN == Double.NaN
res3: Boolean = false
scala> Double.NaN equals Double.NaN
res4: Boolean = true
Edit: Comme cela a été souligné dans un commentaire - "cela se produit également en Java" - dépend de quoi ceci est:
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));
}
Cela va imprimer
false
true
true
Ainsi, le unboxedNan
donne false
par rapport à l'égalité car c'est ainsi que les nombres à virgule flottante IEEE le définissent et cela devrait vraiment arriver dans tous les langages de programmation (bien que cela dérange en quelque sorte avec la notion d'identité) .
Le NaN encadré donne la valeur true pour la comparaison avec ==
in Java car nous comparons les références d’objet.
Je n'ai pas d'explication pour le cas equals
, à mon humble avis, il devrait vraiment se comporter de la même manière que ==
sur les doubles valeurs non encaissées, mais ce n'est pas le cas.
Traduit en Scala le sujet est un peu plus compliqué que Scala a unifié les types primitif et objet dans Any
et se traduit par la primitive double et la boîte double au besoin. Ainsi, le scala ==
se résume apparemment à une comparaison de valeurs primitives NaN
mais equals
utilise celle définie pour les valeurs Double encadrées (il y a beaucoup de magie de conversion implicite en cours et de trucs pimpés sur des doubles par RichDouble
).
Si vous avez vraiment besoin de savoir si quelque chose est réellement NaN
, utilisez isNaN
:
Dans Scala == commencez par vérifier Null valeurs puis appelez égal méthode sur le premier objet