В чем разница между == и .equals в Scala? - PullRequest
133 голосов
/ 07 октября 2011

В чем разница между == и .equals() в Scala и когда, когда их использовать?

Является ли реализация такой же, как в Java?

РЕДАКТИРОВАТЬ: Связанные вопросы говорито конкретных случаях AnyVal.Более общий случай - Any.

Ответы [ 5 ]

183 голосов
/ 07 октября 2011

Обычно вы используете ==, он перенаправляется на equals, за исключением того, что он правильно обрабатывает null s. Ссылочное равенство (редко используется) составляет eq.

33 голосов
/ 07 октября 2011

== является конечным методом и вызывает .equals, который не является окончательным.

Это радикально отличается от Java, где == является оператором, а не методом и строго сравнивает ссылкуравенство для объектов.

26 голосов
/ 26 февраля 2016

TL; DR

  • Переопределить метод equals для сравнения содержимого каждого экземпляра.Это тот же самый метод equals, который используется в Java
  • Используйте оператор == для сравнения, не беспокоясь о null ссылках
  • Используйте метод eq, чтобы проверить, являются ли оба аргумента ТОЧНО та же ссылка.Рекомендуется не использовать, если вы не понимаете, как это работает, и часто equals будет работать вместо того, что вам нужно.И убедитесь, что используете это только с AnyRef аргументами, а не просто Any

ПРИМЕЧАНИЕ. В случае equals, как и в Java, он может не вернуть тот же результат, еслиВы переключаете аргументы, например, 1.equals(BigInt(1)) вернет false, где обратное вернет true.Это связано с тем, что каждая реализация проверяет только определенные типы.Примитивные числа не проверяют, имеет ли второй аргумент типы Number или BigInt, а только другие типы примитивов

Подробности

Метод AnyRef.equals(Any) переопределяется подклассами.Метод из спецификации Java, который также появился в Scala.Если он используется на незарегистрированном экземпляре, он называется в штучной упаковке (хотя он скрыт в Scala; более очевиден в Java с int -> Integer).Реализация по умолчанию просто сравнивает ссылки (как в Java)

Метод Any.==(Any) сравнивает два объекта и позволяет любому аргументу быть нулевым (как если бы вызывал статический метод с двумя экземплярами).Он сравнивает, если оба null, затем вызывает equals(Any) метод в штучной упаковке экземпляра.

Метод AnyRef.eq(AnyRef) сравнивает только ссылки, то есть, где экземпляр находится вобъем памяти.Для этого метода нет явного бокса.

Примеры

  • 1 equals 2 вернет false, поскольку он перенаправляет на Integer.equals(...)
  • 1 == 2вернет false, так как он перенаправляет на Integer.equals(...)
  • 1 eq 2 не скомпилируется, так как требует, чтобы оба аргумента были типа AnyRef
  • new ArrayList() equals new ArrayList() вернет true, при проверке содержимого
  • new ArrayList() == new ArrayList() вернет true, при перенаправлении на equals(...)
  • new ArrayList() eq new ArrayList() вернет false, так как оба аргумента различныэкземпляры
  • foo equals foo вернут true, если foo не равно null, а затем сгенерируют NullPointerException
  • foo == foo и вернут true, даже если foo is null
  • foo eq foo вернет true, так как оба аргумента ссылаются на одну и ту же ссылку
5 голосов
/ 05 февраля 2016

Существует интересная разница между == и equals для Float и Double типов: они трактуют NaN по-разному:

scala> Double.NaN == Double.NaN
res3: Boolean = false

scala> Double.NaN equals Double.NaN
res4: Boolean = true

Редактировать: Как было отмечено в комментарии - «это также происходит в Java» - зависит от того, что именно это :

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));
}

Это напечатает

false
true
true

Итак, unboxedNan дает false при сравнении на равенство, потому что именно так его определяют числа с плавающей запятой IEEE, и это действительно должно происходить в каждом языке программирования (хотя это как-то смешивается с понятием идентичности).

Штрихованный NaN дает true для сравнения, используя == в Java, когда мы сравниваем ссылки на объекты.

У меня нет объяснения для случая equals, ИМХО, он действительно должен вести себя так же, как == для распакованных двойных значений, но это не так.

В переводе на Scala дело обстоит немного сложнее, поскольку Scala объединяет примитивные и объектные типы в Any и переводит в примитивный двойник и коробочный двойник по мере необходимости. Таким образом, scala ==, по-видимому, сводится к сравнению примитивных NaN значений, но equals использует значение, определенное для значений Double в штучной упаковке (происходит много неявного преобразования магии, и есть что-то, что превращается в double с помощью RichDouble).

Если вам действительно нужно выяснить, действительно ли что-то NaN, используйте isNaN:

1 голос
/ 26 декабря 2016

В Scala == сначала проверьте Нулевые значения, а затем вызовите равно методу для первого объекта

...