Przechodzimy do części praktycznej "równości" obiektów w Javie. Trzymamy się kolekcji "HashSet" i rzucam następującymi hasłami: "hashCode" (zwany "kodem mieszającym") i "equals". Jesteście zaciekawieni znaczeń tych słów kluczowych i w jaki sposób mogą pomóc nam przy ustalaniu czy dwa obiekty są sobie równe? Nie pozostaje Wam nic innego jak wchodzić do środka artykułu!

HASHCODE. SPECJALNY KOD MIESZAJĄCY

Hasło w nagłówku nazywane jest również "kodem mieszającym". Jest to nietypowy "zlepek" kilku osobnych informacji, z których powstaje liczba całkowita. Gdy utworzymy sobie dowolny obiekt i wypiszemy na ekranie terminala wywołanie metody "hashCode":

public class Main
{
	public static void main(String[] args)
	{
		String s = "Nowy łańcuch znaków";

		System.out.println(s.hashCode());
	}
}

ujrzymy coś takiego:

HashCode

"hashCode" zależy od wielu czynników których nie sposób wymienić i na nim skupimy swoją uwagę w niniejszym artykule. Poprzednia część wprowadzała kolekcję "HashSet" wraz z teoretycznym wprowadzeniem do samodzielnego definiowania kiedy dwa obiekty możemy uznać za "równe", aby zbiór nie przechowywał dwóch takich samych elementów, bo wtedy jego rola staje się nic niewarta. Wtedy możemy to sobie zamienić na "ArrayList" i dalej efekt jest taki sam, ale nie to jest naszym celem.

Jeżeli nasz "HashSet" albo dowolna inna kolekcja należąca do typu "zbiór" ma rzeczywiście niezawodnie identyfikować identyczność wprowadzanych elementów, musimy przesłonić DWIE metody. Oprócz tej tytułowej, dochodzi jeszcze o nazwie "equals". Obie metody należą do klasy "Object" będącej nazywaną "matką wszystkich obiektów", gdyż od niej pochodzi każda inna klasa. Zatem, pierwszym krokiem na udane weryfikowanie "równości" obiektów jest jawne wprowadzenie obu metod do klasy, która ma przechowywać kryterium identyczności, dokładnie tak, jak to było przy sortowaniu. Oto domyślna struktura:

@Override
public int hashCode()
{
	return super.hashCode();
}

@Override
public boolean equals(Object obj)
{
	return super.equals(obj);
}

Mamy nasze metody "hashCode" oraz "equals". Zauważcie, że jedna zwraca liczbę całkowitą, a druga boolean'a. Zakładam, że wiecie jak "super" wpływa na wywołanie metod. Czas wreszcie zaprezentować w jaki sposób możemy wpływać na sprawdzenie czy jeden obiekt jest taki sam, jak drugi. Odstąpię wyjątkowo od wklejania tego samego kodu. Całość opiera się o ten sam kod zaprezentowany tutaj więc mogę jedynie skupić się metodach wprowadzanych do klasy "Book".

Zacznijmy od tytułu. Załóżmy, że tytuł jest kluczowy którego wartość jest identyczna. Czyli "życiowo" rzecz ujmując, nie trafia się nigdy książka nosząca ten sam tytuł. Zatem, "hashCode" może wyglądać tak:

@Override
public int hashCode()
{
	return title.hashCode();
}

a metoda "equals" wtedy ma wyglądać tak:

@Override
public boolean equals(Object object)
{
	Book book = (Book)object;

	return title.equals(book.title);
}

Jeśli łańcuch znaków ma być unikatowy, to możemy odwołać się do kodu mieszającego pobieranego z łańcucha. Natomiast jeśli uzależniamy weryfikację unikatowości od łańcucha znaków, to MUSIMY również zająć się "equals" i tam operacja wygląda ciut bardziej przerażająca. Rzutujemy obiekt na naszą klasę i wtedy możemy korzystać ze wszystkich jego danych składowych. Jeżeli teraz uruchomicie ten sam program to GWARANTUJĘ, że próba wstawienia książki o tym samym tytule nie będzie wnosiła żadnego efektu. Nie będzie żadnego błędu ani wyjątku, tylko po prostu wywołanie metody będzie "wytłumione", tak samo jakby się wywołało pustą metodę.

Co w przypadku gdybyśmy chcieli uwzględnić nie tylko sam tytuł, ale również autora? Robimy podobnie z tym, że teraz "hashCode" przyjmuje sumę kodów mieszających:

return title.hashCode() + author.hashCode();

a "equals" koniunkcję warunków:

return title.equals(book.title) && author.equals(book.author);

Powinniście już kapować jak to działa. Dzięki takiemu zabiegowi możemy ustalać dowolne kryterium na którym będzie się opierać zbiór celem zweryfikowania czy dodawany element należy "wpuścić" do siebie, czy nie.


Tyle! Mam nadzieję, że wyniesiecie z tego jakąś część i będziecie od tej chwili wiedzieli jak można zlikwidować problem przechowywania duplikatów przez kolekcję u których to w ogóle nie powinno mieć miejsca.

PODOBNE ARTYKUŁY