¿Cuál es la diferencia entre== y.equals en Scala?
scala-java-interop (5)
¿Cuál es la diferencia entre ==
y .equals()
en Scala, y cuándo usar cuál?
¿La implementación es la misma que en Java?
EDIT: la pregunta relacionada habla de casos específicos de AnyVal
. El caso más general es Any
.
TL; DR
- Anular
equals
método para comparar el contenido de cada instancia. Este es el mismo métodoequals
usado en Java - Utilice el operador
==
para comparar, sin preocuparse por referenciasnull
- Use el método
eq
para verificar si ambos argumentos son EXACTAMENTE la misma referencia. Se recomienda que no se use a menos que comprenda cómo funciona esto y, a menudo,equals
a lo que necesita en su lugar. Y asegúrese de usar esto solo con argumentos deAnyRef
, no soloAny
NOTA: En el caso de equals
, al igual que en Java, puede que no devuelva el mismo resultado si cambia los argumentos, por ejemplo 1.equals(BigInt(1))
devolverá false
donde el inverso devolverá true
. Esto se debe a que cada implementación verifica solo tipos específicos. Los números primitivos no comprueban si el segundo argumento es de tipo Number
o BigInt
pero solo de otros tipos primitivos
Detalles
El AnyRef.equals(Any)
es el que se reemplaza por subclases. Un método de la especificación Java que también se ha transferido a Scala. Si se usa en una instancia no empacada, se encuadra para llamar a esto (aunque está oculto en Scala, más obvio en Java con int
-> Integer
). La implementación predeterminada simplemente compara referencias (como en Java)
El método Any.==(Any)
compara dos objetos y permite que cualquiera de los argumentos sea nulo (como llamar a un método estático con dos instancias). Compara si ambos son null
, entonces llama al método equals(Any)
en la instancia en caja.
El AnyRef.eq(AnyRef)
compara solo referencias, es decir, donde la instancia se encuentra en la memoria. No hay boxeo implícito para este método.
Ejemplos
-
1 equals 2
devolveráfalse
, ya que redirige aInteger.equals(...)
-
1 == 2
devolveráfalse
, ya que redirige aInteger.equals(...)
-
1 eq 2
no se compilará, ya que requiere que ambos argumentos sean del tipoAnyRef
-
new ArrayList() equals new ArrayList()
devolverátrue
, ya que verifica el contenido -
new ArrayList() == new ArrayList()
devolverátrue
, ya que redirige aequals(...)
-
new ArrayList() eq new ArrayList()
devolveráfalse
, ya que ambos argumentos son instancias diferentes -
foo equals foo
devolverátrue
, a menos quefoo
seanull
, y luego lanzará unaNullPointerException
-
foo == foo
devolverátrue
, incluso sifoo
esnull
-
foo eq foo
devolverátrue
, ya que ambos argumentos se vinculan a la misma referencia
En Scala == primera comprobación de valores Nulos y luego llama al método igual en el primer objeto
Hay una diferencia interesante entre ==
y equals
para los tipos Float
y Double
: Tratan NaN
diferente:
scala> Double.NaN == Double.NaN
res3: Boolean = false
scala> Double.NaN equals Double.NaN
res4: Boolean = true
Editar: como se señaló en un comentario - "esto también ocurre en Java" - depende de qué es exactamente esto :
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));
}
Esto se imprimirá
false
true
true
Por lo tanto, unboxedNan
produce false
cuando se compara con la igualdad porque así es como lo definen los números flotantes de IEEE y esto debería suceder realmente en todos los lenguajes de programación (aunque de alguna manera se confunde con la noción de identidad).
El NaN encuadrado resulta verdadero para la comparación utilizando ==
en Java, ya que estamos comparando referencias de objetos.
No tengo una explicación para el caso de equals
, en mi humilde opinión, realmente debería comportarse igual que ==
en valores dobles sin caja, pero no es así.
Traducido a Scala, la cuestión es un poco más complicada ya que Scala ha unificado primitivos y tipos de objetos en Any
y se traduce en el doble primitivo y el doble en caja según sea necesario. Por lo tanto, el scala ==
aparentemente se reduce a una comparación de valores NaN
primitivos pero equals
usa el definido en los valores Double en caja (hay una gran cantidad de magia de conversión implícita y RichDouble
en dobles).
Si realmente necesita saber si algo es realmente NaN
use isNaN
:
Normalmente usas ==
, se dirige a equals
, excepto que trata null
s correctamente. La igualdad de referencia (raramente utilizada) es eq
.
==
es un método final, y llama .equals
, que no es final.
Esto es radicalmente diferente que Java, donde ==
es un operador en lugar de un método y compara estrictamente la igualdad de referencia para los objetos.