Niedawno przeczytałem ten dokument dotyczący prac programistycznych .
Dokument jest o definiowaniu hashCode()
i equals()
skutecznie i poprawnie, jednak nie jestem w stanie zrozumieć, dlaczego musimy zastąpić te dwie metody.
Jak mogę podjąć decyzję o wydajnym wdrożeniu tych metod?
Odpowiedzi:
Joshua Bloch mówi o Effective Java
Spróbujmy to zrozumieć na przykładzie tego, co by się stało, gdybyśmy przesłonili
equals()
bez przesłonięciahashCode()
i spróbowali użyćMap
.Że mamy klasę i tak, że dwa obiekty
MyClass
są równe, jeśli ichimportantField
jest równy (zhashCode()
aequals()
generowany przez Eclipse)Zastąp tylko
equals
Jeśli tylko
equals
jest nadpisane, to kiedy zadzwoniszmyMap.put(first,someValue)
pierwszy, będzie mieszał się z jakimś wiadrem, a kiedy zadzwoniszmyMap.put(second,someOtherValue)
, będzie mieszał się z innym wiadrem (ponieważ mają innyhashCode
). Tak więc, mimo że są równe, ponieważ nie mieszają do tego samego segmentu, mapa nie może tego zrealizować i oba pozostają na mapie.Chociaż nie jest to konieczne, aby zastąpić
equals()
jeśli przesłonićhashCode()
, zobaczmy, co się stanie w tym szczególnym przypadku, gdy wiemy, że dwa obiektyMyClass
są równe, jeśli ichimportantField
jest równa, ale nie zastępująequals()
.Zastąp tylko
hashCode
Wyobraź sobie, że masz to
Jeśli przesłonisz tylko
hashCode
wtedy, gdy zadzwoniszmyMap.put(first,someValue)
, najpierw bierze, oblicza jąhashCode
i zapisuje w danym segmencie. Następnie, kiedy zadzwoniszmyMap.put(second,someOtherValue)
, należy najpierw zamienić go na drugi zgodnie z Dokumentacją mapy, ponieważ są one równe (zgodnie z wymaganiami biznesowymi).Problem polega jednak na tym, że równość nie została przedefiniowana, więc kiedy mapa haszy się
second
i iteruje przez segment, sprawdzając, czy istnieje taki obiektk
, którysecond.equals(k)
jest prawdziwy, nie znajdzie go taksecond.equals(first)
, jak będziefalse
.Mam nadzieję, że to było jasne
źródło
if you think you need to override one, then you need to override both of them
jest źle. Musisz przesłonić,hashCode
jeśli twoja klasa zastępuje,equals
ale odwrócenie nie jest prawdą.equals
naruszyłoby umowę zapisaną w javadocObject
: „Jeśli dwa obiekty są równe zgodnie zequals(Object)
metodą, wówczas wywołaniehashCode
metody na każdym z dwóch obiektów musi dać ten sam wynik liczb całkowitych”. Jasne, nie wszystkie części wszystkich umów są wykonywane w całym kodzie, ale formalnie rzecz biorąc, jest to naruszenie i uważam, że to błąd, który czeka.Kolekcje takie jak
HashMap
iHashSet
używają wartości hashcode obiektu w celu ustalenia, jak powinien być przechowywany w kolekcji, a hashcode jest ponownie wykorzystywany w celu zlokalizowania obiektu w jego kolekcji.Pobieranie mieszania jest procesem dwuetapowym:
hashCode()
)equals()
)Oto mały przykład, dlaczego powinniśmy pominąć
equals()
ihashcode()
.Rozważ
Employee
klasę, która ma dwa pola: wiek i imię.Teraz utwórz klasę, wstaw
Employee
obiekt do aHashSet
i sprawdź, czy ten obiekt jest obecny, czy nie.Wydrukuje następujące:
Teraz odkomentuj
hashcode()
metodę, wykonaj to samo, a wynikiem będzie:Czy widzisz teraz, dlaczego jeśli dwa obiekty są uważane za równe, ich kody skrótu również muszą być równe? W przeciwnym razie nigdy nie będziesz w stanie znaleźć obiektu od wartości domyślnej metoda hashcode w klasie Object praktycznie zawsze podaje unikalny numer dla każdego obiektu, nawet jeśli
equals()
metoda zostanie zastąpiona w taki sposób, że dwa lub więcej obiektów uważa się za równe . Nie ma znaczenia, jak równe są obiekty, jeśli ich kody skrótu tego nie odzwierciedlają. A więc jeszcze raz: jeśli dwa obiekty są równe, ich kody skrótu również muszą być równe.źródło
Definiując
equals()
ihashCode()
konsekwentnie, możesz poprawić użyteczność swoich klas jako kluczy w kolekcjach opartych na haszowaniu. Jak wyjaśnia dokument API dla hashCode: „Ta metoda jest obsługiwana na korzyść tabel hasht, takich jak te dostarczane przezjava.util.Hashtable
”.Najlepsza odpowiedź na pytanie dotyczące efektywnego wdrożenia tych metod sugeruje przeczytanie Rozdziału 3 Skutecznej Javy .
źródło
hashCode()
.Mówiąc najprościej, metoda equals w Object Check dla równości referencyjnej, gdzie jako dwie instancje twojej klasy mogą być semantycznie równe, gdy właściwości są równe. Jest to na przykład ważne, gdy umieszczasz swoje obiekty w kontenerze, który używa znaku równości i kodu skrótu, takiego jak HashMap i Set . Powiedzmy, że mamy taką klasę jak:
Tworzymy dwa wystąpienia o tym samym identyfikatorze :
Bez nadpisywania równych otrzymujemy:
Poprawny? Cóż, może jeśli tego właśnie chcesz. Powiedzmy, że chcemy, aby obiekty o tym samym identyfikatorze były tym samym obiektem, niezależnie od tego, czy są to dwa różne wystąpienia. Zastępujemy równe (i hashcode):
Jeśli chodzi o implementację równości i kodu skrótu, mogę polecić użycie metod pomocniczych Guavy
źródło
Tożsamość nie jest równością.
==
tożsamość testu operatora .equals(Object obj)
metoda porównuje test równości (tzn. musimy powiedzieć równość przez przesłonięcie metody)Najpierw musimy zrozumieć zastosowanie metody równości.
Aby odróżnić różnice między dwoma obiektami, musimy zastąpić metodę równości.
Na przykład:
Teraz metoda hashCode może łatwo zrozumieć.
hashCode tworzy liczbę całkowitą w celu przechowywania obiektu w strukturach danych takich jak HashMap , HashSet .
Załóżmy, że mamy metodę zastępowania równą
Customer
jak powyżej,Podczas pracy ze strukturą danych, gdy przechowujemy obiekt w wiadrach (wiadro to fantazyjna nazwa folderu). Jeśli użyjemy wbudowanej techniki skrótu, dla dwóch klientów generuje ona dwa różne kody skrótu. Dlatego przechowujemy ten sam identyczny obiekt w dwóch różnych miejscach. Aby uniknąć tego rodzaju problemów, powinniśmy przesłonić metodę hashCode również w oparciu o następujące zasady.
źródło
Ok, pozwól mi wyjaśnić pojęcie w bardzo prostych słowach.
Po pierwsze, z szerszej perspektywy, mamy kolekcje, a hashapa jest jedną z struktur danych w kolekcjach.
Aby zrozumieć, dlaczego musimy zastąpić zarówno metodę equals, jak i hashcode, w razie potrzeby najpierw zrozumiemy, co jest hashap i co robi.
Hashap jest strukturą danych, która przechowuje pary kluczowych wartości danych w sposób tablicowy. Powiedzmy, że [], gdzie każdy element w „a” jest parą klucz-wartość.
Również każdy indeks w powyższej tablicy może być połączoną listą, dzięki czemu ma więcej niż jedną wartość w jednym indeksie.
Dlaczego teraz używana jest mapa? Jeśli musimy przeszukiwać dużą tablicę, to przeszukujemy każdą z nich, jeśli nie będą one wydajne, więc jaka technika haszowania mówi nam, że pozwala wstępnie przetworzyć tablicę z pewną logiką i pogrupować elementy w oparciu o tę logikę, tj. Mieszanie
np .: mamy tablicę 1,2,3,4,5,6,7,8,9,10,11 i stosujemy mod funkcji skrótu 10, więc 1,11 zostanie zgrupowane razem. Więc jeśli musielibyśmy szukać 11 w poprzedniej tablicy, musielibyśmy iterować całą tablicę, ale kiedy ją pogrupujemy, ograniczamy nasz zakres iteracji, zwiększając w ten sposób szybkość. Ta struktura danych używana do przechowywania wszystkich powyższych informacji może być traktowana jako tablica 2D dla uproszczenia
Teraz oprócz powyższego hashapa mówi również, że nie doda w nim żadnych duplikatów. I to jest główny powód, dla którego musimy zastąpić equals i hashcode
Więc kiedy powiedziano, że wyjaśnia wewnętrzne działanie haszapa, musimy znaleźć metody, które ma haszapa i jak postępuje zgodnie z powyższymi zasadami, które wyjaśniłem powyżej
więc w haszapie jest metoda o nazwie as (K, V) i zgodnie z haszapem powinna ona spełniać powyższe zasady efektywnego rozmieszczania tablicy i nie dodawania żadnych duplikatów
więc to, co robi, polega na tym, że najpierw wygeneruje kod skrótu dla danego klucza, aby zdecydować, w którym indeksie powinna wejść wartość. jeśli nic nie ma w tym indeksie, wówczas nowa wartość zostanie tam dodana, jeśli coś już tam jest następnie nową wartość należy dodać po zakończeniu listy połączonej pod tym indeksem. ale pamiętaj, że nie należy dodawać duplikatów zgodnie z pożądanym zachowaniem mapy skrótów. powiedzmy, że masz dwa obiekty całkowite aa = 11, bb = 11. jak każdy obiekt wyprowadzony z klasy obiektu, domyślną implementacją do porównywania dwóch obiektów jest porównanie referencji, a nie wartości wewnątrz obiektu. Tak więc w powyższym przypadku oba, choć semantycznie równe, nie przejdą testu równości, i istnieje możliwość, że dwa obiekty o tym samym haszu i takich samych wartościach będą istnieć, tworząc w ten sposób duplikaty. Jeśli zastąpimy, moglibyśmy uniknąć dodawania duplikatów. Możesz również odnieść się doSzczegóły pracy
źródło
hashCode()
:Jeśli zastąpisz tylko metodę kodu skrótu, nic się nie stanie. Ponieważ zawsze zwraca nowy
hashCode
dla każdego obiektu jako klasy Object.equals()
:Jeśli przesłonisz tylko metodę równości,
a.equals(b)
to prawda, żehashCode
a i b muszą być takie same, ale nie mogą się zdarzyć. Ponieważ nie zastąpiłeśhashCode
metody.Uwaga:
hashCode()
metoda klasy Object zawsze zwraca nowyhashCode
dla każdego obiektu.Więc kiedy musisz użyć swojego obiektu w kolekcji opartej na haszowaniu, musisz przesłonić oba
equals()
ihashCode()
.źródło
Java ustanawia regułę, że
Tak więc, jeśli w naszej klasie przesłonimy
equals()
, powinniśmy przesłonićhashcode()
metodę, aby przestrzegać tej reguły. Obie metody,equals()
ihashcode()
są wykorzystywane wHashtable
, na przykład, do przechowywania wartości jako par klucz-wartość. Jeśli zastąpimy jedno, a nie drugie, istnieje możliwość, żeHashtable
mogą one nie działać tak, jak chcemy, jeśli użyjemy takiego obiektu jako klucza.źródło
Ponieważ jeśli ich nie zastąpisz, zastosujesz domyślną implantację w Object.
Biorąc pod uwagę, że równość instancji i wartości hascode na ogół wymagają wiedzy o tym, co składa się na obiekt, na ogół będą musiały zostać przedefiniowane w twojej klasie, aby miały jakiekolwiek konkretne znaczenie.
źródło
Aby używać własnych obiektów klasy jako kluczy w kolekcjach takich jak HashMap, Hashtable itp., Powinniśmy przesłonić obie metody (hashCode () i equals ()), mając świadomość wewnętrznego działania kolekcji. W przeciwnym razie prowadzi to do błędnych wyników, których nie oczekujemy.
źródło
Dodanie do odpowiedzi @Lombo
Kiedy trzeba zastąpić equals ()?
Domyślna implementacja Object's equals () to
co oznacza, że dwa obiekty będą uważane za równe tylko wtedy, gdy będą miały ten sam adres pamięci, co będzie prawdziwe tylko wtedy, gdy porównasz obiekt ze sobą.
Ale możesz rozważyć dwa obiekty takie same, jeśli mają taką samą wartość dla jednej lub więcej ich właściwości (zobacz przykład podany w odpowiedzi @Lombo).
Więc
equals()
w tych sytuacjach przejdziecie na manowce i dacie własne warunki równości.Z powodzeniem zaimplementowałem equals () i działa świetnie. Dlaczego oni również proszą o zastąpienie hashCode ()?
No cóż, dopóki nie używasz kolekcji opartych na „Hash” w klasie zdefiniowanej przez użytkownika, jest w porządku. Jednak jakiś czas w przyszłości może chcesz użyć
HashMap
alboHashSet
a jeśli nieoverride
i „prawidłowo wdrożyć” hashCode () , to zbiór Hash opiera się nie działać będzie zgodnie z przeznaczeniem.Zastąp tylko równa się (dodatek do odpowiedzi @Lombo)
Przede wszystkim HashMap sprawdza, czy hashCode
second
jest taki sam jakfirst
. Tylko jeśli wartości są takie same, przejdzie do sprawdzenia równości w tym samym segmencie.Ale tutaj hashCode jest inny dla tych 2 obiektów (ponieważ mają one inny adres pamięci niż domyślna implementacja). Dlatego nie będzie nawet obchodzić sprawdzania równości.
Jeśli masz punkt przerwania w przesłoniętej metodzie equals (), nie wkroczyłby, gdyby miały różne kody skrótu.
contains()
sprawdzahashCode()
i tylko jeśli są takie same, wywołałoby to twojąequals()
metodę.Dlaczego nie możemy sprawić, by HashMap sprawdzał równość we wszystkich segmentach? Nie ma więc potrzeby zastępowania hashCode () !!
Brakuje Ci punktu kolekcji opartych na haszowaniu. Rozważ następujące :
Poniżej przedstawiono klucze przechowywane w postaci wiader.
Powiedzmy, że chcesz wiedzieć, czy mapa zawiera klucz 10. Czy chcesz przeszukać wszystkie wiadra? lub Czy chcesz przeszukać tylko jedną łyżkę?
Na podstawie kodu hashCode można stwierdzić, że jeśli 10 jest obecne, musi być obecne w segmencie 1. Zatem przeszukiwany będzie tylko segment 1!
źródło
hashCode()
do określenia segmentu i użyjeequals()
metody, aby sprawdzić, czy wartość jest już obecna w segmencie . Jeśli nie, zostanie dodany, w przeciwnym razie zostanie zastąpiony bieżącą wartościąhashCode()
najpierw do znalezienia Wpisu (segmentu) iequals()
do znalezienia wartości we Wpisiejeśli oba zostaną zastąpione,
Mapa < >
jeśli równa się nie zostanie zastąpione
Mapa < >
Jeśli hashCode nie zostanie zastąpione
Mapa < >
HashCode Equal Contract
źródło
Rozważ zbieranie piłek w wiadrze w kolorze czarnym. Twoim zadaniem jest pokolorowanie tych kulek w następujący sposób i użycie ich do odpowiedniej gry,
Do tenisa - żółty, czerwony. Do krykieta - biały
Teraz wiadro ma kulki w trzech kolorach: żółtym, czerwonym i białym. I że teraz zrobiłeś kolorowanie Tylko ty wiesz, który kolor jest dla której gry.
Farbowanie kul - Hashowanie. Wybór piłki do gry - równa się.
Jeśli zrobiłeś kolorowanie i ktoś wybrał piłkę do gry w krykieta lub tenisa, to nie przeszkadza kolor !!!
źródło
Patrzyłem na wyjaśnienie „Jeśli tylko przesłonisz hashCode, to kiedy wywołujesz
myMap.put(first,someValue)
, bierze on pierwszy, oblicza jego hashCode i przechowuje go w danym segmencie. Następnie, gdy wywołujeszmyMap.put(first,someOtherValue)
, należy go zastąpić drugim, zgodnie z Dokumentacją mapy, ponieważ są one równe (zgodnie z naszą definicją). ” :Myślę, że drugi raz, kiedy dodajemy
myMap
, powinien to być „drugi” obiekt jakmyMap.put(second,someOtherValue)
źródło
1) Typowy błąd pokazano w poniższym przykładzie.
zielony samochód nie został znaleziony
2. Problem spowodowany przez hashCode ()
Problem jest spowodowany przez nie zastąpioną metodę
hashCode()
. Umowa międzyequals()
ihashCode()
jest:Jeśli dwa obiekty mają ten sam kod skrótu, mogą być lub nie być równe.
źródło
Jest to przydatne podczas korzystania z obiektów wartości . Oto fragment z Portland Pattern Repository :
źródło
Załóżmy, że masz klasę (A), która agreguje dwie inne (B) (C), i musisz przechowywać instancje (A) w tablicy hasht. Domyślna implementacja pozwala jedynie na rozróżnienie instancji, ale nie według (B) i (C). Tak więc dwa wystąpienia A mogą być równe, ale domyślnie nie pozwala na ich prawidłowe porównanie.
źródło
Metody równe i kod skrótu są zdefiniowane w klasie obiektowej. Domyślnie, jeśli metoda równa zwraca true, system przejdzie dalej i sprawdzi wartość kodu skrótu. Jeśli kod skrótu 2 obiektów jest również taki sam, wówczas obiekty zostaną uznane za takie same. Jeśli więc zastąpisz tylko metodę równości, to nawet jeśli metoda przesłonięcia równości wskazuje 2 obiekty, które mają być równe, zdefiniowany przez system kod skrótu może nie wskazywać, że 2 obiekty są równe. Musimy więc również przesłonić kod skrótu.
źródło
true
doequals
nie będą traktowane jako dopasowywania. Z drugiej strony, jeśli zdarzają się zbiory, zauważ, że rzeczy nie mogą mieć tego samego kodu skrótu, prawdopodobnie nie zauważą, że są równe.Metody Equals i Hashcode w Javie
Są to metody klasy java.lang.Object, która jest superklasą wszystkich klas (także klas niestandardowych i innych zdefiniowanych w API Java).
Realizacja:
public boolean equals (Object obj)
Ta metoda sprawdza po prostu, czy dwa odwołania do obiektów xiy odnoszą się do tego samego obiektu. tj. Sprawdza, czy x == y.
Jest zwrotny: dla każdej wartości odniesienia x, x.equals (x) powinno zwracać wartość true.
Jest symetryczny: dla dowolnych wartości referencyjnych x i y wartość x.equals (y) powinna zwracać wartość true tylko wtedy, gdy y.equals (x) zwraca wartość true.
Jest przechodnie: dla dowolnych wartości referencyjnych x, y i z, jeśli x.equals (y) zwraca true, a y.equals (z) zwraca true, to x.equals (z) powinno zwracać true.
Jest spójny: dla dowolnej wartości referencyjnej x i y wielokrotne wywołania x.equals (y) konsekwentnie zwracają wartość true lub konsekwentnie zwracają wartość false, pod warunkiem, że żadna informacja używana w porównaniach równości obiektu nie jest modyfikowana.
public int hashCode ()
Ta metoda zwraca wartość kodu skrótu dla obiektu, na który wywoływana jest ta metoda. Ta metoda zwraca wartość kodu skrótu jako liczbę całkowitą i jest obsługiwana na korzyść klas kolekcji opartych na haszowaniu, takich jak Hashtable, HashMap, HashSet itp. Metodę tę należy zastąpić w każdej klasie, która przesłania metodę równości.
Ogólna umowa hashCode to:
Za każdym razem, gdy jest wywoływana w tym samym obiekcie więcej niż jeden raz podczas wykonywania aplikacji Java, metoda hashCode musi konsekwentnie zwracać tę samą liczbę całkowitą, pod warunkiem, że żadna informacja użyta w porównaniach równych obiektu nie jest modyfikowana.
Ta liczba całkowita nie musi pozostać spójna od jednego wykonania aplikacji do innego wykonania tej samej aplikacji.
Jeśli dwa obiekty są równe zgodnie z metodą equals (Object), wówczas wywołanie metody hashCode na każdym z dwóch obiektów musi dać ten sam wynik w postaci liczby całkowitej.
Nie jest wymagane, aby jeśli dwa obiekty były nierówne zgodnie z metodą equals (java.lang.Object), wówczas wywołanie metody hashCode na każdym z dwóch obiektów musi dawać różne wyniki liczb całkowitych. Programiści powinni jednak pamiętać, że uzyskiwanie wyraźnych wyników liczb całkowitych dla nierównych obiektów może poprawić wydajność tablic mieszających.
Zasoby:
JavaRanch
Obrazek
źródło
W poniższym przykładzie, jeśli skomentujesz zastąpienie dla equals lub hashcode w klasie Person, ten kod nie sprawdzi kolejności Toma. Korzystanie z domyślnej implementacji kodu skrótu może powodować błędy w przeglądaniu skrótów.
Mam poniżej uproszczony kod, który wyświetla zamówienie ludzi według Person. Osoba jest używana jako klucz w tablicy mieszającej.
źródło
Klasy ciągów i klasy opakowań mają różną implementację
equals()
ihashCode()
metody niż klasa Object. Metoda equals () klasy Object porównuje odwołania do obiektów, a nie do zawartości. Metoda hashCode () klasy Object zwraca odrębny kod skrótu dla każdego obiektu, niezależnie od tego, czy zawartość jest taka sama.Prowadzi to do problemu, gdy używasz kolekcji Map, a klucz jest typu Trwałego, typu StringBuffer / builder. Ponieważ nie zastępują equals () i hashCode () w przeciwieństwie do klasy String, equals () zwróci false, gdy porównasz dwa różne obiekty, mimo że oba mają tę samą zawartość. Sprawi, że hashMap będzie przechowywać te same klucze zawartości. Przechowywanie tych samych kluczy treści oznacza, że narusza zasadę Mapy, ponieważ Mapa w ogóle nie zezwala na duplikowanie kluczy. Dlatego zastępujesz metody equals () oraz hashCode () w swojej klasie i udostępniasz implementację (IDE może wygenerować te metody), aby działały tak samo jak String's equals () i hashCode () i zapobiegały tym samym kluczom treści.
Musisz zastąpić metodę hashCode () wraz z equals (), ponieważ equals () działa zgodnie z hashcode.
Ponadto przesłanianie metody hashCode () wraz z equals () pomaga zachować nienaruszony kontrakt equals () - hashCode (): „Jeśli dwa obiekty są równe, muszą mieć ten sam kod skrótu”.
Kiedy trzeba napisać niestandardową implementację dla hashCode ()?
Jak wiemy, wewnętrzne działanie HashMap opiera się na zasadzie Hashing. Istnieją pewne segmenty, w których zapisywane są zestawy danych. Dostosowujesz implementację hashCode () zgodnie z wymaganiami, aby obiekty tej samej kategorii mogły być przechowywane w tym samym indeksie. gdy przechowujesz wartości w kolekcji Map za pomocą
put(k,v)
metody, wewnętrzna implementacja put () to:Oznacza to, że generuje indeks, a indeks jest generowany na podstawie kodu skrótu określonego obiektu klucza. Tak więc, aby ta metoda generowała kod skrótu zgodnie z wymaganiami, ponieważ te same zestawy kodów zostaną zapisane w tym samym segmencie lub indeksie.
Otóż to!
źródło
hashCode()
Metoda służy do uzyskania unikalnej liczby całkowitej dla danego obiektu. Ta liczba całkowita jest używana do określania położenia segmentu, gdy ten obiekt musi być przechowywany w niektórychHashTable
,HashMap
takich jak struktura danych. Domyślnie Object'shashCode()
metoda zwraca i całkowitą reprezentację adresu pamięci, w którym przechowywany jest obiekt.hashCode()
Metoda obiektów jest używany, gdy wstawiamy je doHashTable
,HashMap
lubHashSet
. Więcej na tematHashTables
na Wikipedii w celach informacyjnych.Aby wstawić dowolny wpis w strukturze danych mapy, potrzebujemy zarówno klucza, jak i wartości. Jeśli zarówno klucz, jak i wartości są typami danych definiowanymi przez użytkownika,
hashCode()
klucz określa, gdzie należy przechowywać obiekt wewnętrznie. Gdy konieczne będzie również wyszukanie obiektu na mapie, kod skrótu klucza określi, gdzie szukać obiektu.Kod skrótu wskazuje tylko wewnętrznie pewien „obszar” (lub listę, segment itd.). Ponieważ różne obiekty kluczy mogą potencjalnie mieć ten sam kod skrótu, sam kod skrótu nie gwarantuje, że zostanie znaleziony odpowiedni klucz.
HashTable
Potem iteracje ten obszar (wszystkie klawisze z tym samym kodem hash) i korzysta z kluczykaequals()
metodę, aby znaleźć odpowiedni klucz. Po znalezieniu odpowiedniego klucza zwracany jest obiekt przechowywany dla tego klucza.Tak więc, jak widzimy, kombinacja metod
hashCode()
iequals()
jest używana podczas przechowywania i wyszukiwania obiektów w plikuHashTable
.UWAGI:
Zawsze używaj tych samych atrybutów obiektu do wygenerowania
hashCode()
iequals()
obu. Podobnie jak w naszym przypadku, użyliśmy identyfikatora pracownika.equals()
musi być spójny (jeśli obiekty nie są modyfikowane, wówczas musi zwracać tę samą wartość).Ilekroć
a.equals(b)
,a.hashCode()
musi być taki sam jakb.hashCode()
.Jeśli zastąpisz jedno, powinieneś zastąpić drugie.
http://parameshk.blogspot.in/2014/10/examples-of-comparable-comporator.html
źródło
hashCode()
nie jest używany do zwracania unikalnej liczby całkowitej dla każdego obiektu. To jest niemożliwe. Sam temu zaprzeczasz w drugim zdaniu czwartego akapitu.IMHO, to zgodnie z regułą - jeśli dwa obiekty są równe, powinny mieć taki sam skrót, tzn. Równe obiekty powinny wytwarzać równe wartości skrótu.
Biorąc pod uwagę powyższe, default equals () w Object jest ==, który dokonuje porównania adresu, hashCode () zwraca adres w liczbie całkowitej (skrót w rzeczywistym adresie), który jest znowu odrębny dla odrębnego Object.
Jeśli chcesz użyć niestandardowych obiektów w kolekcjach opartych na skrócie, musisz przesłonić zarówno equals () i hashCode (), przykład Jeśli chcę zachować zestaw skrótów obiektów pracownika, jeśli nie użyję silniejszego kodu skrótu i równa się Mogę ostatecznie zastąpić dwa różne obiekty pracownika, dzieje się tak, gdy używam wieku jako hashCode (), jednak powinienem używać unikalnej wartości, którą może być identyfikator pracownika.
źródło
Aby pomóc Ci w sprawdzeniu zduplikowanych obiektów, potrzebujemy niestandardowego znaku równości i kodu skrótu.
Ponieważ hashcode zawsze zwraca liczbę, zawsze jest on w stanie szybko pobrać obiekt za pomocą liczby zamiast klawisza alfabetycznego. Jak to zrobi Załóżmy, że utworzyliśmy nowy obiekt, przekazując pewną wartość, która jest już dostępna w innym obiekcie. Teraz nowy obiekt zwróci tę samą wartość skrótu co inny obiekt, ponieważ przekazana wartość jest taka sama. Po zwróceniu tej samej wartości skrótu JVM za każdym razem przechodzi do tego samego adresu pamięci, a jeśli w przypadku tej samej wartości skrótu występuje więcej niż jeden obiekt, użyje metody equals () do zidentyfikowania poprawnego obiektu.
źródło
Jeśli chcesz przechowywać i odzyskiwać swój niestandardowy obiekt jako klucz w Mapie, zawsze powinieneś nadpisywać equals i hashCode w swoim niestandardowym obiekcie. Na przykład:
Tutaj p1 i p2 będą traktowane jako tylko jeden obiekt, a
map
rozmiar będzie wynosił tylko 1, ponieważ są one równe.źródło
Klasa testowa
W klasie obiektowej równa się (Object obj) służy do porównywania porównania adresów, dlatego w klasie testowej, jeśli porównujesz dwa obiekty, to równa się metoda dająca fałsz, ale gdy zastąpimy hashcode (), może porównać zawartość i dać odpowiedni wynik.
źródło
Jeśli przesłonisz
equals()
i niehashcode()
, nie znajdziesz żadnego problemu, chyba że ty lub ktoś inny użyje tego typu klasy w takiej kolekcji mieszanejHashSet
. Ludzie przede mną wielokrotnie wyjaśniali udokumentowaną teorię, jestem tutaj, aby podać bardzo prosty przykład.Zastanów się nad klasą, która
equals()
musi oznaczać coś dostosowanego:Teraz rozważ tę główną klasę:
To da następujące wyniki:
Cieszę się z wyników. Ale jeśli nie przesłonię
hashCode()
, spowoduje to koszmar, ponieważ obiekty o tejRishav
samej zawartości członka nie będą już traktowane jako unikalne, ponieważhashCode
będą się różnić, ponieważ są generowane domyślnie, oto wynik:źródło
Obie metody są zdefiniowane w klasie Object. Oba są w najprostszej realizacji. Więc kiedy potrzebujesz, chcesz dodać więcej implementacji do tych metod, wtedy masz nadpisanie w swojej klasie.
Dla Ex: metoda equals () w obiekcie sprawdza tylko równość w odniesieniu do referencji. Więc jeśli potrzebujesz również porównać jego stan, możesz to zmienić, tak jak dzieje się to w klasie String.
źródło
Bah - „Musisz zastąpić hashCode () w każdej klasie, która przesłania equals ().”
[z Effective Java, autor: Joshua Bloch?]
Czy to nie jest odwrotna sytuacja? Przesłanianie hashCode prawdopodobnie oznacza, że piszesz klasę klucza skrótu, ale przesłonięcie równości na pewno nie. Istnieje wiele klas, które nie są używane jako klucze skrótu, ale chcą metody testowania równości logicznej z innego powodu. Jeśli wybierzesz dla niego opcję „równa się”, możesz zostać upoważniony do napisania implementacji hashCode poprzez nadgorliwe stosowanie tej reguły. Wszystko, co osiąga, to dodawanie nieprzetestowanego kodu do bazy kodów, zło czekające na potknięcie się w przyszłości. Pisanie kodu, którego nie potrzebujesz, jest również zwinny. To po prostu źle (a ide wygenerowany prawdopodobnie nie będzie kompatybilny z twoimi ręcznie stworzonymi równościami).
Czy na pewno powinni byli ustanowić interfejs dla obiektów napisanych jako klucze? Niezależnie od tego, Object nigdy nie powinien zapewniać domyślnego hashCode () i equals () imho. Prawdopodobnie zachęciło to wiele zepsutych kolekcji skrótów.
Ale w każdym razie myślę, że „zasada” jest zapisana od początku. W międzyczasie będę nadal unikać używania metody „równa się” do metod testowania równości :-(
źródło