Nadpisanie hashCode i ==
Część sekcji Programowanie obiektowe ścieżki Dart w Coddy. Lekcja 71 z 110.
Domyślnie dwa obiekty w Dart są równe tylko wtedy, gdy są dokładnie tą samą instancją w pamięci. Oznacza to, że dwa obiekty o identycznych wartościach nadal są uznawane za różne:
class Point {
int x, y;
Point(this.x, this.y);
}
void main() {
var p1 = Point(3, 4);
var p2 = Point(3, 4);
print(p1 == p2); // false - różne instancje!
}Aby porównywać obiekty na podstawie ich wartości, musisz przeciążyć zarówno operator ==, jak i hashCode. Te dwa elementy zawsze należy przeciążać razem — jeśli dwa obiekty są równe, muszą mieć ten sam kod skrótu:
class Point {
final int x, y;
Point(this.x, this.y);
@override
bool operator ==(Object other) {
if (other is! Point) return false;
return x == other.x && y == other.y;
}
@override
int get hashCode => Object.hash(x, y);
}
void main() {
var p1 = Point(3, 4);
var p2 = Point(3, 4);
print(p1 == p2); // true - te same wartości!
}hashCode ma kluczowe znaczenie dla kolekcji takich jak Set oraz kluczy Map. Funkcja pomocnicza Object.hash() w Dart łączy wiele wartości w jeden kod skrótu. Bez prawidłowego hashCode obiekty nie będą działać poprawnie w kolekcjach opartych na kodach skrótu, nawet jeśli nadpisano ==.
Wyzwanie
ŁatwyZbudujmy system współrzędnych, w którym punkty można porównywać na podstawie ich wartości, a nie adresów pamięci! Utworzysz klasę Coordinate, która prawidłowo implementuje równość opartą na wartościach, dzięki czemu będzie działać poprawnie przy sprawdzaniu równości i w kolekcjach opartych na skrótach, takich jak Set.
Podzielisz kod na dwa pliki:
coordinate.dart: Utwórz klasęCoordinatereprezentującą punkt w przestrzeni 2D, z polamifinal int xifinal int y. Przeciąż zarówno operator==, jak ihashCode, aby dwie współrzędne o takich samych wartościach x i y były uznawane za równe. UżyjObject.hash(), aby wygenerować kod skrótu na podstawie obu pól.main.dart: Zaimportuj plik ze współrzędnymi i pokaż, jak równość oparta na wartościach zmienia sposób porównywania obiektów:- Utwórz dwa osobne obiekty
Coordinate, oba z x:5i y:10 - Wypisz, czy są równe, używając
== - Wypisz, czy są identyczne (ta sama instancja), używając
identical() - Utwórz
Set<Coordinate>i dodaj do niego obie współrzędne - Wypisz długość zbioru (powinna wynosić 1, ponieważ współrzędne są równe!)
- Utwórz trzecią współrzędną z x:
3i y:7, a następnie dodaj ją do zbioru - Wypisz końcową długość zbioru
- Utwórz dwa osobne obiekty
To wyzwanie pokazuje, dlaczego hashCode i == należy zawsze przeciążać razem. Set używa kodów skrótu do organizowania elementów, więc bez prawidłowego hashCode nawet równe obiekty mogą być przechowywane jako duplikaty!
Oczekiwany wynik:
true
false
1
2Spróbuj swoich sił
import 'coordinate.dart';
void main() {
// TODO: Utwórz dwa osobne obiekty Coordinate, oba z x: 5 i y: 10
// TODO: Wypisz, czy są równe, używając ==
// TODO: Wypisz, czy są identyczne (czy to ta sama instancja), używając identical()
// TODO: Utwórz Set<Coordinate> i dodaj do niego obie współrzędne
// TODO: Wypisz liczbę elementów zbioru (powinna wynosić 1, ponieważ są równe!)
// TODO: Utwórz trzecią współrzędną z x: 3 i y: 7 i dodaj ją do zbioru
// TODO: Wypisz końcową liczbę elementów zbioru
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP
Pliki zewnętrzneBiblioteki i importyWprowadzenie do OOPKlasy a obiektySłowo kluczowe thisMetodyZmienne instancjiPodstawy konstruktorówPowtórka – prosty kalkulator4Bezpieczeństwo wartości null
Wprowadzenie do bezpieczeństwa wartości nullTypy dopuszczające null i niedopuszczające nullOperatory ? i !Słowo kluczowe late a bezpieczeństwo wartości nullOperatory uwzględniające nullBezpieczeństwo wartości null w klasachPodsumowanie — system profili użytkowników7Klasy abstrakcyjne i interfejsy
Klasy abstrakcyjneMetody abstrakcyjneInterfejsy w DartInterfejsy niejawneImplementowanie a rozszerzanieWiele interfejsówPowtórka — kalkulator kształtów10Kolekcje i typy generyczne
Przegląd List, Set i MapKolekcje bezpieczne typowoKlasy generyczneMetody generyczneOgraniczenia typów generycznychIterable i IteratorPowtórka — generyczne przechowywanie danych13Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieMetody rozszerzająceKlasy wywoływalneKlasy zapieczętowane (Dart 3)Rekordy (Dart 3)Wzorce i dopasowywanie (3.0)Typy wyliczeniowe z metodami16Projekt: Zarządzanie biblioteką
Omówienie projektuKlasy książek i użytkowników2Konstruktory w Dart
Konstruktor domyślnyKonstruktory nazwaneListy inicjalizująceKonstruktory stałeKonstruktory fabryczneKonstruktory przekierowującePodsumowanie — budowanie kształtów5Hermetyzacja
Elementy publiczne a prywatneKonwencja prefiksu _Prywatność na poziomie bibliotekiGettery i settery — szczegółowoUkrywanie informacjiPodsumowanie — dane uczniów8Domieszki
Wprowadzenie do domieszekTworzenie domieszekKorzystanie z wielu domieszekSłowo kluczowe on w domieszkachDomieszka a dziedziczenieDomieszka a interfejsPodsumowanie – system zwierząt11Metody specjalne
Nadpisanie toString()Nadpisanie hashCode i ==Interfejs ComparableMetoda call()Nadpisanie noSuchMethodPodsumowanie — własna kolekcja14Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec Strategy3Właściwości klas
Elementy instancji a elementy statycznePola final i constZmienne inicjalizowane z opóźnieniemMetody i pola statyczneGettery i setteryPowtórzenie – menedżer kont bankowych6Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe superPrzesłanianie metodAdnotacja @overrideSłowo kluczowe final dla klasKonstruktory i dziedziczeniePowtórzenie – hierarchia pracowników9Polimorfizm
Podstawy polimorfizmuPolimorfizm za pomocą interfejsówSprawdzanie typu w czasie działaniaOperatory is i asSłowo kluczowe covariantPodsumowanie — procesor płatnościPoćwicz samodzielnie: Kompilator Dart online