scala scala-java-interop

¿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étodo equals usado en Java
  • Utilice el operador == para comparar, sin preocuparse por referencias null
  • 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 de AnyRef , no solo Any

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 a Integer.equals(...)
  • 1 == 2 devolverá false , ya que redirige a Integer.equals(...)
  • 1 eq 2 no se compilará, ya que requiere que ambos argumentos sean del tipo AnyRef
  • new ArrayList() equals new ArrayList() devolverá true , ya que verifica el contenido
  • new ArrayList() == new ArrayList() devolverá true , ya que redirige a equals(...)
  • new ArrayList() eq new ArrayList() devolverá false , ya que ambos argumentos son instancias diferentes
  • foo equals foo devolverá true , a menos que foo sea null , y luego lanzará una NullPointerException
  • foo == foo devolverá true , incluso si foo es null
  • 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.