Jaka jest różnica między ==
i .equals()
w Scala, a kiedy używać które?
Czy implementacja jest taka sama jak w Javie?
EDYCJA: Powiązane pytanie dotyczy konkretnych przypadków AnyVal
. Bardziej ogólny przypadek to Any
.
Jaka jest różnica między ==
i .equals()
w Scala, a kiedy używać które?
Czy implementacja jest taka sama jak w Javie?
EDYCJA: Powiązane pytanie dotyczy konkretnych przypadków AnyVal
. Bardziej ogólny przypadek to Any
.
Odpowiedzi:
Zwykle używasz ==
, kieruje do equals
, z wyjątkiem tego, że traktuje je null
poprawnie. Równość odwołań (rzadko używana) to eq
.
3 == BigInt(3)
i BigInt(3) == 3
są prawdziwe. Ale 3.equals(BigInt(3))
jest fałszywe, podczas gdy BigInt(3).equals(3)
jest prawdziwe. Dlatego wolę używać ==
. Unikaj używania equals()
w scali. Myślę, że ==
niejawna konwersja dobrze equals()
działa , ale tak nie jest.
new java.lang.Integer(1) == new java.lang.Double(1.0)
jest prawdziwe, podczas gdy new java.lang.Integer(1) equals new java.lang.Double(1.0)
jest fałszywe?
equals
, aby porównać zawartość każdego wystąpienia. To ta sama equals
metoda, która jest używana w Javie==
operatora do porównania, nie martwiąc się o null
odwołaniaeq
metody, aby sprawdzić, czy oba argumenty są DOKŁADNIE tym samym odwołaniem. Zaleca się, aby nie używać, chyba że rozumiesz, jak to działa i często equals
będzie działać w przypadku tego, czego potrzebujesz. I upewnij się, że używasz tego tylko z AnyRef
argumentami, a nie tylkoAny
UWAGA: W przypadku equals
, tak jak w Javie, może nie zwrócić tego samego wyniku, jeśli zmienisz argumenty, np. 1.equals(BigInt(1))
Zwróci false
tam, gdzie zwróci odwrotność true
. Dzieje się tak, ponieważ każda implementacja sprawdza tylko określone typy. Liczby pierwotne nie sprawdzają, czy drugi argument jest typu Number
nor, BigInt
ale tylko innych typów pierwotnych
AnyRef.equals(Any)
Metoda jest jedną zastąpione przez podklasy. Metoda ze specyfikacji Java, która również trafiła do Scali. Jeśli jest używany w instancji bez opakowania, jest zaznaczony, aby to wywołać (choć ukryty w Scali; bardziej oczywiste w Javie z int
-> Integer
). Domyślna implementacja jedynie porównuje referencje (jak w Javie)
Any.==(Any)
Sposób porównuje dwa przedmioty i pozwala oba argumenty będą puste (jak wywołanie statyczne metody z dwóch przypadkach). Porównuje, jeśli oba są null
, a następnie wywołuje equals(Any)
metodę w pudełkowej instancji.
AnyRef.eq(AnyRef)
Sposób porównuje tylko odniesienia, to jest, gdy przykład znajduje się w pamięci. W przypadku tej metody nie ma niejawnego boksu.
1 equals 2
powróci false
, ponieważ przekierowuje doInteger.equals(...)
1 == 2
powróci false
, ponieważ przekierowuje doInteger.equals(...)
1 eq 2
nie skompiluje się, ponieważ wymaga, aby oba argumenty były typu AnyRef
new ArrayList() equals new ArrayList()
zwróci true
, ponieważ sprawdza zawartośćnew ArrayList() == new ArrayList()
powróci true
, ponieważ przekierowuje doequals(...)
new ArrayList() eq new ArrayList()
zwróci false
, ponieważ oba argumenty są różnymi wystąpieniamifoo equals foo
zwróci true
, chyba że foo
jest null
, a następnie wyrzuciNullPointerException
foo == foo
powróci true
, nawet jeśli foo
jestnull
foo eq foo
zwróci wartość true
, ponieważ oba argumenty prowadzą do tego samego odwołaniaIstnieje interesująca różnica między typami ==
i equals
dla Float
oraz Double
: traktują one NaN
inaczej:
scala> Double.NaN == Double.NaN
res3: Boolean = false
scala> Double.NaN equals Double.NaN
res4: Boolean = true
Edit: Jak wskazano w komentarzu - „tak się dzieje również w Javie” - zależy od tego, co dokładnie to jest:
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));
}
To się wydrukuje
false
true
true
Tak więc unboxedNan
wydajność false
porównana pod kątem równości, ponieważ tak definiują ją liczby zmiennoprzecinkowe IEEE i powinno to naprawdę mieć miejsce w każdym języku programowania (chociaż w jakiś sposób miesza się z pojęciem tożsamości).
Pole NaN daje wartość true dla porównania używanego ==
w Javie, gdy porównujemy odwołania do obiektów.
Nie mam wytłumaczenia dla equals
sprawy, IMHO to naprawdę powinno zachowywać się tak samo jak ==
na unboxed double wartości, ale tak nie jest.
W tłumaczeniu na Scala sprawa jest trochę bardziej skomplikowana, ponieważ Scala ujednolicił typy prymitywne i obiektowe na Any
i tłumaczy na prymitywne podwójne i pudełkowe podwójne w razie potrzeby. Tak więc skala ==
najwyraźniej sprowadza się do porównania NaN
wartości pierwotnych , ale equals
wykorzystuje tę zdefiniowaną na opakowanych wartościach Double (dzieje się wiele niejawnej magii konwersji i jest coś podwojonego przez podwójne RichDouble
).
Jeśli naprawdę chcesz się dowiedzieć, czy coś jest rzeczywiście NaN
używane isNaN
: