У чому різниця між 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 не компілюється, оскільки для цього потрібні обидва аргументи 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 він дійсно повинен поводитись так само, як і ==у необов’язаних подвійних значеннях, але це не так.
У перекладі на Scala справа є дещо складнішою, оскільки Scala об'єднав примітивні та об'єктні типи в Anyта перекладає на примітивний подвійний та в коробковий подвійний, якщо це потрібно. Таким чином, масштаб, ==очевидно, зводиться до порівняння примітивних NaNзначень, але equalsвикористовує одне, визначене в коробкових подвійних значеннях (відбувається безліч неявних магічних перетворень, і речі, прикріплені до подвоєнь RichDouble).
Якщо вам дійсно потрібно з’ясувати, чи щось насправді NaNвикористовується isNaN: