В чем разница между ==
и .equals()
в Scala и когда какой использовать?
Реализация такая же, как в Java?
РЕДАКТИРОВАТЬ: в соответствующем вопросе говорится о конкретных случаях AnyVal
. Более общий случай Any
.
В чем разница между ==
и .equals()
в Scala и когда какой использовать?
Реализация такая же, как в Java?
РЕДАКТИРОВАТЬ: в соответствующем вопросе говорится о конкретных случаях AnyVal
. Более общий случай Any
.
scala.Equals
котором указывается на Программирование на Scala, глава 28, Равенство объектов .
Ответы:
Обычно вы используете ==
, он направляет equals
, за исключением того, что обрабатывает null
s правильно. Ссылочное равенство (используется редко) есть eq
.
3 == BigInt(3)
и BigInt(3) == 3
верны. Но 3.equals(BigInt(3))
это ложь, тогда BigInt(3).equals(3)
как правда. Поэтому предпочитаю использовать ==
. Избегайте использования equals()
в scala. Я думаю, ==
что неявное преобразование хорошо, но equals()
нет.
new java.lang.Integer(1) == new java.lang.Double(1.0)
же правда, а new java.lang.Integer(1) equals new java.lang.Double(1.0)
ложь?
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 (как при вызове статического метода с двумя экземплярами). Он сравнивает, если оба они есть 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
for 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 в штучной упаковке (происходит много неявной магии преобразования, и есть вещи, которые накладываются на двойные значения RichDouble
).
Если вам действительно нужно узнать, действительно ли что-то NaN
используется isNaN
: