Quelle est la différence entre ==
et .equals()
dans Scala, et quand utiliser lequel?
L'implémentation est-elle la même qu'en Java?
EDIT: La question connexe parle de cas spécifiques de AnyVal
. Le cas le plus général est Any
.
Quelle est la différence entre ==
et .equals()
dans Scala, et quand utiliser lequel?
L'implémentation est-elle la même qu'en Java?
EDIT: La question connexe parle de cas spécifiques de AnyVal
. Le cas le plus général est Any
.
Réponses:
Vous utilisez normalement ==
, il achemine vers equals
, sauf qu'il traite null
s correctement. L'égalité de référence (rarement utilisée) est eq
.
3 == BigInt(3)
et BigInt(3) == 3
sont vrais. Mais, 3.equals(BigInt(3))
est faux, alors que BigInt(3).equals(3)
c'est vrai. Par conséquent, préférez utiliser ==
. Évitez d'utiliser equals()
dans scala. Je pense ==
que la conversion implicite bien, mais equals()
pas.
new java.lang.Integer(1) == new java.lang.Double(1.0)
est-ce vrai alors que new java.lang.Integer(1) equals new java.lang.Double(1.0)
c'est faux?
equals
méthode pour comparer le contenu de chaque instance. C'est la même equals
méthode utilisée en Java==
opérateur pour comparer, sans vous soucier des null
référenceseq
méthode pour vérifier si les deux arguments sont exactement la même référence. Il est recommandé de ne pas utiliser à moins que vous ne compreniez comment cela fonctionne et fonctionnera souvent equals
pour ce dont vous avez besoin à la place. Et assurez-vous de ne l'utiliser qu'avec des AnyRef
arguments, pas seulementAny
REMARQUE: dans le cas de equals
, tout comme en Java, il peut ne pas renvoyer le même résultat si vous changez d'arguments, par exemple 1.equals(BigInt(1))
retournera false
là où l'inverse retournera true
. Cela est dû au fait que chaque implémentation ne vérifie que des types spécifiques. Les nombres primitifs ne vérifient pas si le deuxième argument est de types Number
ni BigInt
mais uniquement d'autres types primitifs
La AnyRef.equals(Any)
méthode est celle remplacée par les sous-classes. Une méthode de la spécification Java qui est également venue à Scala. S'il est utilisé sur une instance sans boîte, il est encadré pour l'appeler (bien que caché dans Scala; plus évident en Java avec int
-> Integer
). L'implémentation par défaut compare simplement les références (comme en Java)
La Any.==(Any)
méthode compare deux objets et autorise l'un ou l'autre des arguments à être nul (comme pour appeler une méthode statique avec deux instances). Il compare si les deux sont null
, puis il appelle la equals(Any)
méthode sur une instance encadrée.
La AnyRef.eq(AnyRef)
méthode compare uniquement les références, c'est-à-dire l'emplacement de l'instance en mémoire. Il n'y a pas de boxe implicite pour cette méthode.
1 equals 2
reviendra false
, car il redirige versInteger.equals(...)
1 == 2
reviendra false
, car il redirige versInteger.equals(...)
1 eq 2
ne compilera pas, car les deux arguments doivent être de type AnyRef
new ArrayList() equals new ArrayList()
reviendra true
, car il vérifie le contenunew ArrayList() == new ArrayList()
reviendra true
, car il redirige versequals(...)
new ArrayList() eq new ArrayList()
retournera false
, car les deux arguments sont des instances différentesfoo equals foo
sera de retour true
, à moins foo
est null
, puis va lancer uneNullPointerException
foo == foo
sera de retour true
, même si foo
estnull
foo eq foo
retournera true
, puisque les deux arguments sont liés à la même référenceIl existe une différence intéressante entre ==
et equals
pour Float
et les 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 ce que c'est exactement :
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 imprimera
false
true
true
Donc, les unboxedNan
rendements false
comparés pour l'égalité parce que c'est ainsi que les nombres à virgule flottante IEEE le définissent et cela devrait vraiment se produire dans chaque langage de programmation (bien que cela perturbe en quelque sorte la notion d'identité).
Le NaN encadré donne vrai pour la comparaison utilisant ==
en Java pendant que nous comparons les références d'objet.
Je n'ai pas d'explication pour le equals
cas, ==
à mon humble avis , il devrait vraiment se comporter de la même manière que sur les valeurs doubles sans boîte, mais ce n'est pas le cas.
Traduit en Scala, la question est un peu plus compliquée car Scala a unifié les types primitifs et objets en Any
et se traduit par le double primitif et le double encadré si nécessaire. Ainsi, la scala ==
se résume apparemment à une comparaison de NaN
valeurs primitives mais equals
utilise celle définie sur les valeurs Double encadrées (il y a beaucoup de magie de conversion implicite en cours et il y a des choses qui sont pimpées sur des doubles RichDouble
).
Si vous avez vraiment besoin de savoir si quelque chose est réellement NaN
utilisé isNaN
: