Metody equals i hashCode oraz ich kontrakt

Obie te metody są metodami pochodzącymi z klasy Object i implementacja obu tych metod powinna być jedną z pierwszych rzeczy, którą zrobimy.

Metoda equals — służy w Javie do porównywania typów obiektowych. Czyli czy obiekty ‘znaczą to samo’ (czy mają tą samą wartość) bardziej niż czy ‘są tym samym obiektem’.

Metoda hashCode() służy do zwrócenia unikalnej wartości liczbowej (typu int) dla każdego unikalnego obiektu. Jej zadaniem jest wygenerowanie dla obiektu szybkiego skrótu (hashu) w formie liczby całkowitej.

Pomiędzy tymi metodami został zdefiniowany kontrakt.

  • Jeżeli dwa obiekty są sobie równe (wg metody equals), to ich hashCode również musi być równy.
  • Jeżeli obiekty są różne (wg metody equals), to ich hashCode może być równy, jednak ze względów wydajnościowych powinno to być unikalne. Dla przykładu:
  • Każde wywołanie metody hashCode na tym samym obiekcie musi kończyć się zwróceniem tej samej liczby całkowitej.
  • Relacja wyznaczona metodą equals musi być zwrotna (reflexive), czyli dla każdej zmiennej x różnej od null wyrażenie x.equals(x) musi zwracać wartość = true.
  • Relacja wyznaczona metodą equals musi być symetryczna (symmetric), czyli dla każdej pary zmiennych x i y, wyrażenie x.equals(y) ma wartość true i wtedy i tylko wtedy gdy y.equals(x) = true.
  • Relacja wyznaczona metodą equals musi być przechodnia (transitive), czyli dla dowolnych zmiennych x, y i z, jeżeli x.equals(y) = true oraz y.equals(z) = true, to x.equals(z) musi również = true.
  • Relacja wyznaczona metodą equals musi być spójna (consistent), czyli każdorazowe wywołanie x.equals(y) (przy założeniu, że między wywołaniami obiekty nie były modyfikowane) zawsze musi zwracać tę samą wartość – zawsze true albo zawsze false.
  • każdy obiekt jest różny od null, czyli wywołanie x.equals(null) dla obiektu x różnego od null, zawsze musi zwrócić false.

Teraz pozostaje kwestia dlaczego to jest takie ważne?

Załóżmy że mamy kolekcje danych operującą na HashMapie które przechowują dane w tablicach mieszających a tablice kubełki. Każdy kubełek przechowuje zaś wartości w postaci klucz-wartość. Gdy więc wstawiamy element do mapy za pomocą metody „put” – wyliczany jest hashCode dla klucza i na tej podstawie indeks kubełka pod którym zostanie umieszczony dany element. Dla przykładu w uproszczeniu wyobraźmy sobie że wstawiamy obiekt typu String „aa” dla którego klucza hashCode został wyliczony jako 100 i dlatego obiekt trafia do kubełka nr 1. Dla klucza obiektu „bb” i hashCode jest równy 200 i jest umieszczony w kubełku nr 2.

map.put("aa", 5); //hashCode 100
map.put("bb", 6); //hashCode 200

Może zdarzyć się jednak tak że klucz kolejnego obiektu może mieć ten sam numer hasCodu np:

 map.put("zz", 6); //hashCode 100

Leave a Comment

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *