Какая разница между == и .equals в Scala?

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

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

EDIT: связанный с этим вопрос говорит о конкретных случаях AnyVal. Более общий случай Any.

Ответ 1

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

Ответ 2

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

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

Ответ 3

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. Если он используется в unboxed экземпляре, он помещается в это окно (хотя скрывается в Scala, более очевидным в Java с intInteger). Реализация по умолчанию просто сравнивает ссылки (как в 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 есть null
  • foo eq foo вернет true, поскольку оба аргумента ссылаются на одну и ту же ссылку

Ответ 4

Существует интересное различие между == и 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 получается истинное значение для сравнения с использованием == в Java, поскольку мы сравниваем ссылки на объекты.

У меня нет объяснений для случая equals, IMHO он должен вести себя так же, как == по unboxed double values, но это не так.

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

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

Ответ 5

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