equals() i hashCode()
Część sekcji Programowanie obiektowe ścieżki Java w Coddy. Lekcja 42 z 87.
Podczas porównywania obiektów w Javie operator == sprawdza, czy dwa odwołania wskazują tę samą lokalizację w pamięci. Aby porównać rzeczywistą zawartość obiektów, musisz nadpisać metodę equals().
public class Person {
private String name;
private int age;
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && name.equals(person.name);
}
}Metoda equals() opiera się na standardowym wzorcu: najpierw sprawdź, czy to ten sam obiekt, następnie zweryfikuj typ, a na końcu porównaj odpowiednie pola.
Za każdym razem, gdy przesłaniasz equals(), musisz również przesłonić hashCode(). To umowa w Java: obiekty, które są równe, muszą mieć ten sam kod skrótu. Kolekcje oparte na kodach skrótu, takie jak HashMap i HashSet, polegają na tej zasadzie, aby działać poprawnie.
@Override
public int hashCode() {
return Objects.hash(name, age);
}Metoda narzędziowa Objects.hash() generuje kod skrótu z tych samych pól, które są używane w equals(). Jeśli dwa obiekty Person mają takie samo imię i wiek, zostaną uznane za równe i wygenerują identyczne kody skrótu, co zapewni spójne działanie w kolekcjach.
Wyzwanie
ŁatwyStwórzmy system ewidencji studentów, który prawidłowo implementuje równość obiektów. Utworzysz klasę Student, w której dwóch studentów jest uznawanych za równych, jeśli mają ten sam identyfikator studenta i imię, niezależnie od tego, czy są tym samym obiektem w pamięci.
Rozmieścisz swój kod w dwóch plikach:
Student.java: Utwórz klasę reprezentującą studenta z trzema polami prywatnymi:studentId(String),name(String) igpa(double). Dodaj konstruktor inicjalizujący wszystkie pola oraz metody pobierające dla każdego pola.Nadpisz metodę
equals(), aby dwa obiekty Student były uznawane za równe, gdy mają ten samstudentIdORAZ tę samą wartośćname. Zastosuj standardowy schemat: sprawdź, czy to ta sama referencja, sprawdź, czy obiekt nie jest null i czy ma odpowiedni typ, a następnie porównaj odpowiednie pola.Nadpisz metodę
hashCode(), używającObjects.hash()z tymi samymi polami, które są używane wequals(). Pamiętaj, aby zaimportowaćjava.util.Objectsna początku pliku.Main.java: Ożyw swoją klasę Student, porównując obiekty studentów. Otrzymasz sześć danych wejściowych reprezentujących dwóch studentów: najpierw identyfikator, imię i GPA pierwszego studenta, a następnie identyfikator, imię i GPA drugiego studenta.Utwórz oba obiekty Student, a następnie wykonaj trzy porównania i wypisz wyniki:
- Wypisz
Same reference:, a następnie informację, czy pierwszy student jest równy samemu sobie (powinno to zawsze być true) - Wypisz
Content equality:, a następnie informację, czy pierwszy student jest równy drugiemu studentowi (na podstawie implementacji equals) - Wypisz
Hash codes match:, a następnie informację, czy obaj studenci mają ten sam kod skrótu
- Wypisz
Otrzymasz sześć danych wejściowych: identyfikator pierwszego studenta (String), imię pierwszego studenta (String), GPA pierwszego studenta (double), identyfikator drugiego studenta (String), imię drugiego studenta (String) oraz GPA drugiego studenta (double).
Zauważ, że gdy dwóch studentów ma takie same identyfikatory i imiona, equals() zwraca true ORAZ ich kody skrótu są zgodne. To jest kontrakt, którego musisz przestrzegać!
Spróbuj swoich sił
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Wczytaj dane pierwszego studenta
String id1 = scanner.nextLine();
String name1 = scanner.nextLine();
double gpa1 = scanner.nextDouble();
scanner.nextLine(); // pomiń znak nowej linii
// Wczytaj dane drugiego studenta
String id2 = scanner.nextLine();
String name2 = scanner.nextLine();
double gpa2 = scanner.nextDouble();
// TODO: Utwórz dwa obiekty Student, korzystając z danych wejściowych
// TODO: Wypisz "Same reference: ", a następnie informację, czy student1 jest równy samemu sobie
// TODO: Wypisz "Content equality: ", a następnie informację, czy student1 jest równy student2
// TODO: Wypisz "Hash codes match: ", a następnie informację, czy obaj studenci mają ten sam kod skrótu
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe thisMetodyPola (atrybuty)Metoda konstruktoraPrzeciążanie konstruktoraPodsumowanie — prosty kalkulator4Dziedziczenie
Podstawy dziedziczenia (extends)Słowo kluczowe superPrzesłanianie metod (@Override)Łańcuch wywołań konstruktorówKlasa ObjectDziedziczenie jedno- i wielopoziomoweDlaczego Java nie obsługuje wielodziedziczenia klasPodsumowanie – hierarchia pracowników7Metody specjalne i klasa Object
Metoda toString()equals() i hashCode()Metoda clone()compareTo() i ComparableInterfejs ComparatorPodsumowanie — własne sortowanie10Obsługa wyjątków w programowaniu obiektowym
Hierarchia klas wyjątkówWłasne wyjątkiBłędy sprawdzane a niesprawdzaneWzorzec try-with-resourcesPodsumowanie – zweryfikowany użytkownik2Modyfikatory dostępu i enkapsulacja
Przegląd poziomów dostępuMetody pobierające i ustawiająceUkrywanie informacjiSłowo kluczowe finalPodsumowanie — menedżer kont bankowych5Polimorfizm
Podstawy przeciążania metodPrzesłanianie metod (w czasie wykonywania)Rzutowanie w górę i w dółOperator instanceofKlasy i metody abstrakcyjnePowtórka — kalkulator figur8Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieAgregacja a kompozycjaKlasy wewnętrzne, zagnieżdżone i anonimoweEnumy i metody enumówRekordy (Java 16+)Klasy zapieczętowane (Java 17+)11Wzorce projektowe — część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec BuilderWzorzec ObserverWzorzec Strategy3Właściwości klas i składowe statyczne
Zmienne instancji a zmienne statyczneMetody statyczneBloki statyczneStałe (static final)Powtórka – Counter i Utility6Interfejsy i klasy abstrakcyjne
Wprowadzenie do interfejsówImplementowanie interfejsówImplementacja wielu interfejsówMetody domyślne i statyczne w interfejsieKlasy abstrakcyjne a interfejsyInterfejsy funkcyjnePodsumowanie — system płatnościPoćwicz samodzielnie: Kompilator Java online