В чем разница между == и .equals() в Scala, а когда использовать какой?
Является ли реализация такой же, как в Java?
EDIT: связанный с этим вопрос говорит о конкретных случаях AnyVal. Более общий случай Any.
В чем разница между == и .equals() в Scala, а когда использовать какой?
Является ли реализация такой же, как в Java?
EDIT: связанный с этим вопрос говорит о конкретных случаях AnyVal. Более общий случай Any.
Обычно вы используете ==, он маршрутизируется на equals, за исключением того, что он правильно относится к null. Ссылочный равенство (редко используется) eq.
== является окончательным методом и вызывает .equals, что не является окончательным.
Это радикально отличается от Java, где == - это оператор, а не метод и строго сравнивает ссылочное равенство для объектов.
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 с 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 не будет компилироваться, так как для обоих аргументов требуется тип AnyRefnew ArrayList() equals new ArrayList() вернет true, поскольку он проверяет содержимоеnew ArrayList() == new ArrayList() вернет true, поскольку он перенаправляет на equals(...)new ArrayList() eq new ArrayList() вернет false, поскольку оба аргумента являются разными экземплярамиfoo equals foo вернет true, если только foo не является null, тогда будет выбрано значение NullPointerExceptionfoo == foo вернет true, даже если foo есть nullfoo eq foo вернет true, поскольку оба аргумента ссылаются на одну и ту же ссылкуСуществует интересное различие между == и 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:
В Scala == сначала проверьте значения Null, а затем вызовите метод equals для первого объекта