У чому різниця між Scala ==
і .equals()
в якому, і коли його використовувати?
Чи реалізація така, як у Java?
EDIT: Пов'язане питання стосується конкретних випадків AnyVal
. Більш загальний випадок Any
.
У чому різниця між Scala ==
і .equals()
в якому, і коли його використовувати?
Чи реалізація така, як у Java?
EDIT: Пов'язане питання стосується конкретних випадків AnyVal
. Більш загальний випадок Any
.
Відповіді:
Ви зазвичай використовуєте ==
, він спрямовується до equals
, за винятком того, що він null
належним чином поводиться з. Довідкова рівність (рідко використовується) є eq
.
3 == BigInt(3)
і те BigInt(3) == 3
, і інше . Але, 3.equals(BigInt(3))
помилково, тоді як BigInt(3).equals(3)
це правда. Тому віддайте перевагу використанню ==
. Уникайте використання equals()
в масштабі. Я думаю, що ==
це неявна конверсія добре, але 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
, тоді він викликає 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 він дійсно повинен поводитись так само, як і ==
у необов’язаних подвійних значеннях, але це не так.
У перекладі на Scala справа є дещо складнішою, оскільки Scala об'єднав примітивні та об'єктні типи в Any
та перекладає на примітивний подвійний та в коробковий подвійний, якщо це потрібно. Таким чином, масштаб, ==
очевидно, зводиться до порівняння примітивних NaN
значень, але equals
використовує одне, визначене в коробкових подвійних значеннях (відбувається безліч неявних магічних перетворень, і речі, прикріплені до подвоєнь RichDouble
).
Якщо вам дійсно потрібно з’ясувати, чи щось насправді NaN
використовується isNaN
: