В чем разница между ==
и .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
, который не является окончательным.Это радикально отличается от Java, где
==
оператор, а не метод, строго сравнивает ссылочное равенство для объектов.источник
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 (как при вызове статического метода с двумя экземплярами). Он сравнивает, если оба они есть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
forFloat
и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
:источник
В Scala == сначала проверьте значения Null, а затем вызовите метод equals для первого объекта
источник