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