Jak domyślne pliki .equals i .hashCode będą działać dla moich klas?

106

Powiedz, że mam własną klasę

public class MyObj { /* ... */ }

Ma pewne atrybuty i metody. NIE implementuje equals, NIE implementuje hashCode.

Kiedy wywołamy equals i hashCode, jakie są domyślne implementacje? Z klasy Object? A czym one są? Jak będzie działać domyślna równość? Jak będzie działał domyślny hashCode i co zwróci? == po prostu sprawdzi, czy odwołują się do tego samego obiektu, więc jest to łatwe, ale co z metodami equals () i hashCode ()?

alexeypro
źródło

Odpowiedzi:

94

Tak, domyślną implementacją jest Object (ogólnie rzecz biorąc; jeśli dziedziczysz z klasy, która przedefiniowała equals i / lub hashCode, zamiast tego użyjesz tej implementacji).

Z dokumentacji:

equals

Metoda equals dla klasy Object implementuje najbardziej rozróżniającą relację równoważności obiektów; to znaczy, dla wszelkich niezerowych wartości odniesienia xiy, ta metoda zwraca prawdę wtedy i tylko wtedy, gdy x i y odnoszą się do tego samego obiektu (x == y ma wartość true).

hashCode

O ile jest to rozsądnie praktyczne, metoda hashCode zdefiniowana przez klasę Object zwraca różne liczby całkowite dla różnych obiektów. (Jest to zwykle realizowane poprzez konwersję adresu wewnętrznego obiektu na liczbę całkowitą, ale ta technika implementacji nie jest wymagana przez język programowania JavaTM).

Etienne de Martel
źródło
50

Z Objectjednego z wdrożeń JVM:

public boolean equals(Object object) {
    return this == object;
}

public int hashCode() {
    return VMMemoryManager.getIdentityHashCode(this);
}

W obu przypadkach wystarczy porównać adresy pamięci przedmiotowych obiektów.

Brad Mace
źródło
7
Z jakiej wersji JDK to pochodzi? W v6u23 ea:public native int hashCode();
khachik
@kha - Masz rację, myślę, że wyśledziłem jedną z natywnych implementacji, aby zobaczyć, co tak naprawdę zrobiła
Brad Mace
10

Istnieją domyślne implementacje equals()i hashCode()w Object. Jeśli nie podasz własnej implementacji, zostaną one użyte. Dla equals(), oznacza to ==porównania: obiekty będą równe tylko wtedy, gdy są one dokładnie tego samego obiektu. Dla hashCode()The Javadoc ma dobre wytłumaczenie.

Aby uzyskać więcej informacji, patrz Efektywna Java, Rozdział 3 (pdf), punkt 8.

Jorn
źródło
1

Tak, z Objectklasy, ponieważ Twoja klasa niejawnie rozszerza Object. equalspo prostu wraca this == obj. hashCodeimplementacja jest natywna. Zgaduję - zwraca wskaźnik do obiektu.

chaczik
źródło
2
Jest to wskaźnik do obiektu znajdującego się w pamięci, ale nie jest to adres pamięciowy obiektu. GC może przesuwać obiekt w pamięci, a kod skrótu pozostanie taki sam.
Jeremy
@Jeremy Thanks. stackoverflow.com/questions/2427631/… może być interesujący.
chaczik
1

Jeśli nie podasz własnej implementacji, zostanie użyta implementacja pochodząca z Object. To jest OK, chyba że planujesz umieścić swoje instancje klasy w np. HashSet (dowolnej kolekcji, która faktycznie używa hashCode ()), lub czymś, co musi sprawdzić równość obiektu (np. Metoda zawiera () HashSet). W przeciwnym razie będzie działać nieprawidłowo, jeśli o to prosisz.

Zapewnienie własnej implementacji tych metod jest dość łatwe dzięki HashCodeBuilder i EqualsBuilder z Apache Commons Lang .

Paweł Dyda
źródło
(a) Dlaczego mówisz, że „domyślna implementacja„ równa się ”klasy Object nie będzie działać poprawnie z HashSet? Jest to sprzeczne z innymi odpowiedziami na tej stronie. (b) Dziękujemy za linki Commons Lang.
Basil Bourque
1
@Basil: Nie sądzę, żeby to zaprzeczało. Oczywiście domyślna implementacja zadziała ... jakoś, ale nie tak, jak się spodziewasz. To znaczy, ponieważ equals () używa równości odwołań, dwa identyczne obiekty byłyby „różne” w oczach domyślnej implementacji. W rezultacie możesz mieć dwa różne wystąpienia dokładnie tej samej rzeczy w swoim zestawie. A raczej typowe użycie Zestawów jest wtedy, gdy chcesz wyeliminować duplikaty ...
Paweł Dyda
@ PawełDyda: Domyślne zachowanie jest ogólnie poprawne dla typów zmiennych. Jeśli Fooi Barsą odwołaniami do dwóch różnych instancji typu mutowalnego i istnieje metoda (np. SomeMutatingMethod) Taka, Foo.SomeMutatingMethod()która nie wpływa w Barten sam sposób Foo, różnica ta powinna wystarczyć, aby uznać obiekty za nierówne.
supercat
0

Dział deweloperów IBM mówi:

W tej domyślnej implementacji dwa odwołania są równe tylko wtedy, gdy odnoszą się do dokładnie tego samego obiektu. Podobnie, domyślna implementacja hashCode () udostępniana przez Object jest uzyskiwana przez odwzorowanie adresu pamięci obiektu na wartość całkowitą.

Jednak, aby mieć pewność co do dokładnych szczegółów implementacji dla wersji Java konkretnego dostawcy, prawdopodobnie najlepiej będzie wyglądać jak źródło (jeśli jest dostępne)

brabster
źródło