Ten sam hashCode

0

Przeczytałem taki tekst:

jeżeli wartość hashCode dla 2 obiektów jest taka sama, to obiekty te mogą być równoznaczne (innymi słowy equals może zwrócić true lub false)

Jakim cudem może zwrócić false w przypadku takiego samego hashCodu ? Jeżeli obiekty są w tym samym miejscu w pamięciu, to chyba nie mogą być różne

3

Polecam rzucić okiem na fantastyczne wytłumaczenie od @jarekr000000 - hashCode() - explain the magic :-)

1

hashCode z Objecta nie jest adresem w pamięci, może być co najwyżej na jego podstawie obliczony. Przede wszystkim obiektów danego typu może być więcej niż możliwych hashCode'ów, więc poleganie na unikalności hashCode'a jest naiwne i błędne.

identityHashCode czyli hashCode z Objecta jest używany rzadko, bo przy nadpisywaniu equalsa musisz nadpisać hashCode'a. Jeśli dwa obiekty są równe (tzn equals zwraca true) to muszą mieć taki sam hashCode. Stały hashCode, np hashCode zawsze równy 1 spełnia kontrakt equals/hashCode dla każdego equalsa.

Używanie standardowego hashCode z Objecta jest nie tylko błędne w większości przypadków, ale także ma negatywny wpływ na wydajność. Oryginalny hashCode z Objecta jest liczony na podstawie adresu obiektu, ale obiekty podczas GC (garbage collection) zmieniają swój adres. Z tego wynika, że jeśli identity hash code było policzone na obiekcie, to GC musi tego hashCode'a gdzieś zapisać podczas kompaktowania sterty. Zamiast dokładać nowe pole do każdego Objecta JVM ma osobną mapę z zapisanymi hashCode'ami. Więcej szczegółów np tutaj: https://stackoverflow.com/q/3796699 Zapisywanie hashCode'a musi być ponieważ identitty hashCode dla tego samego obiektu nie może się zmieniać.

Polecam wyguglować frazę: "equals hashcode contract".

0

Gugluję i kolejna rzecz mnie interesuje:

@Override
 public int hashCode() {
     return 17 * model.hashCode() + 31 * manufacturer.hashCode() + 7 * productionYear;
 }

tak mniej więcej znalazłem w 2 poradnikach, własną implementację hashCode, ale w żadnym nie ma napisane dlaczego akurat takie liczby jak 17,31 czy 7.
Można wpisywać randomowe liczby ?

1

Są to liczby pierwsze - dzięki temu zmniejsza się szansa na kolizję.

0

Dodatkowo żeby nie złamać kontraktu, nie można implementować equals bez hashcode, pytanie czy można hashcode bez equals ? Moim zdaniem tak. W czym mogłoby to przeszkadzać ?

1

Zarówno zabawy z liczeniem hashCode'a jak i to, że stały hashCode pasuje do każdego equalsa (także domyślnego) opisał @jarekr000000 w przytoczonym poście, więc nie trzeba chyba powtarzać.

Przy zachowanym kontrakcie implikacja między equals, a hashCode jest taka: jeśli a.equals(b) to a.hashCode() == b.hashCode(). W drugą stronę implikacja nie zachodzi i nie może zachodzić w ogólności, bo możesz mieć więcej różnych obiektów niż jest możliwych wartości hashCode.

1

@watpliwosci można zaimplementować tylko hashcode, tylko ze pewnie skończy się to obniżeniem wydajności. Ale można.

1 użytkowników online, w tym zalogowanych: 0, gości: 1