Jason. Cała informatyka w jednym miejscu!

Następna porcja wiedzy na temat kolekcji w Javie. Wcześniej poruszyłem temat kolekcji "TreeSet", a teraz dowiemy się co nieco o bardzo podobnej kolekcji zwanej "HashSet" w języku Java. Przy okazji będzie wstęp do rozumienia "równości" obiektów. Zapraszam po szczegóły.

"HASHSET" W JĘZYKU JAVA. WYJAŚNIENIE SENSU ZBIORU

W poprzednim artykule wspomniałem powierzchownie o zbiorach i jaki jest sens ich wykorzystywania. Zbiór jest kolekcją, która ma za zadanie "pilnować", aby nie został dodany jakikolwiek duplikat. Byliśmy wtedy świadkami jak "TreeSet" nie spełniał tej cechy i wystarczyło podać tylko inny rok nawet z tymi samymi danymi, aby książka "weszła" do kolekcji. Obie kolekcje są ze sobą powiązane i to dosłownie, bo implementują ten sam interfejs jakim jest "Set". Jednak "HashSet" w języku Java, w przeciwieństwie do "TreeSet", nie zajmuje się sortowaniem i to nie jest jego "natura". On ma za zadanie jedynie przechowywanie samych unikatowych elementów.

Ten artykuł nie skończy się na samym przedstawieniu kolekcji "HashSet", ale też zajmiemy się tematem implementacji kryterium identyczności (równości) obiektów. Dowiecie się także dlaczego należy odróżniać równość odwołań i równość obiektów oraz czym grozi zignorowanie definicji kryteriów, na jakie trzeba spoglądać, aby uznać dwa obiekty za identyczne!

"RÓWNOŚĆ" OBIEKTÓW, CZYLI JAK ROZUMIEĆ USTALANIE IDENTYCZNOŚCI

Przytoczmy raz kolejny przykład z książką jednak zamieniając kolekcję na "HashSet". Najpierw sobie skopiujcie te kody źródłowe, potem skompilujcie i uruchomcie program:

KLASA "MAIN"

public class Main
{
	public static void main(String[] args)
	{
		new Launcher();
	}
}

KLASA "BOOK"

public class Book
{
	private final String title, author, publisher;
	private final int year;

	public Book(String author, String title, String publisher, int year)
	{
		this.author = author;
		this.title = title;
		this.publisher = publisher;
		this.year = year;
	}

	@Override
	public String toString()
	{
		return author + ". " + title + ". " + publisher + ", " + year;
	}
}

KLASA "LAUNCHER"

import java. util.HashSet;

public class Launcher
{
	private HashSet<Book> books;

	public Launcher()
	{
		createInstances();
		addBooks();
		printBooks();
	}

	private void createInstances()
	{
		books = new HashSet<>();
	}

	private void addBooks()
	{
		books.add(new Book("Adam Mickiewicz", "Pan Tadeusz", "Aleksander Jełowicki", 1834));
		books.add(new Book("Gustaw Herling-Grudziński", "Inny świat", "Roy", 1951));
		books.add(new Book("Aleksander Głowacki", "Lalka", "Gebethner i Wolff", 1890));
		books.add(new Book("Adam Mickiewicz", "Pan Tadeusz", "Aleksander Jełowicki", 1834));
	}

	private void printBooks()
	{
		System.out.println("WYPISYWANIE KOLEKCJI:");
		books.forEach(System.out::println);
	}
}

Po uruchomieniu programu, ujrzycie cztery książki, z czego jedna się powtórzy nawet bez zmiany jakiegokolwiek parametru! To wyraźny sygnał, że "HashSet" w języku Java nie spełnia swojej roli w należyty sposób. Doświadczacie właśnie problemu związanego z ustalaniem kiedy dwa obiekty są sobie "równe". Dzielą się na dwa rodzaje: równość odwołań i równość obiektów.

Równość odwołań polega na weryfikacji tożsamości obu instancji czy ich adresy referencji się ze sobą pokrywają. Możemy dowieść, że dwa obiekty są sobie równe na podstawie ich odwołań tworząc jeden obiekt w jednej zmiennej i przypisując TEN SAM obiekt do drugiej zmiennej. "Kodowo" wyglądałoby to tak:

Integer integerA = new Integer(52);
Integer integerB = integerA;

System.out.println(integerA.equals(integerB));

Dodawanie do "HashSet" kolejnych elementów wymaga zastosowania tego drugiego rodzaju, równości obiektów. Ten rodzaj równości z kolei gra pierwsze skrzypce w momencie, gdy następuje próba dodania obiektu do zbioru. To trochę tak, jakbyśmy przekazali zbiorowi zestaw cech na kartce, na jakie musi spoglądać, żeby kandydat został dopuszczony (coś jak rozmowa kwalifikacyjna). W języku Java taki zestaw cech dla kolekcji "HashSet", określa się poprzez przesłonięcie dwóch metod: "hashCode" i "equals" (więcej w osobnym materiale). Obie należą do klasy "Object" - klasy wszystkich klas. Za ich pomocą tworzy się kryterium dla selekcji obiektów, które mają zostać uznane za wyjątkowe (i tym samym dopuszczone do zbioru). Najprościej rzecz ujmując, musimy zbadać czy oba obiekty posiadają identyczną wartość jakiejś danej składowej (albo wielu).

Jakie kryterium jest szczególnie ważne w naszym przypadku? Dla książki powinniśmy uwzględniać przede wszystkim tytuł, a najlepiej ISBN, bo na pewno dwa razy nie trafi się taki sam. Jeśli dany tytuł składa się z kilku tomów, musimy też uwzględnić numer tomu jednej i drugiej książki (ewentualnie numer wydania). Może również zaistnieć taki przypadek, że mamy dwie książki o tym samym tytule, ale mogą mieć innych autorów. Jak widzicie, jest kilka wariantów.

"HashSet" w języku Java

"HashSet" w języku Java należy do kolekcji typu "zbiór" i jego podstawowym zadaniem jest zapewnienie, żeby żaden nowo wstawiany element nie był duplikatem już istniejącego. Kluczową sprawą jest logiczne zdefiniowanie "równości obiektów".


Dalsza część o równości obu obiektów dla kolekcji "HashSet" w języku Java została zawarta w tym artykule, bo trzeba rozdzielić teorię od praktyki. Bywajcie!

PODOBNE ARTYKUŁY