Redéfinition de hashCode & ==
Fait partie de la section Programmation Orientée Objet du Journey Dart de Coddy — leçon 71 sur 110.
Par défaut, deux objets en Dart ne sont égaux que s'ils sont la même instance exacte en mémoire. Cela signifie que deux objets ayant des valeurs identiques sont toujours considérés comme différents :
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 - instances différentes !
}Pour comparer des objets par leurs valeurs, vous devez redéfinir à la fois l'opérateur == et hashCode. Ces deux-là doivent toujours être redéfinis ensemble - si deux objets sont égaux, ils doivent avoir le même code de hachage :
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 - mêmes valeurs !
}Le hashCode est crucial pour les collections comme les clés de Set et de Map. L'assistant Object.hash() de Dart combine plusieurs valeurs en un seul code de hachage. Sans un hashCode approprié, vos objets ne fonctionneront pas correctement dans les collections basées sur le hachage, même si == est redéfini.
Défi
FacileConstruisons un système de coordonnées où les points peuvent être comparés par leurs valeurs plutôt que par leurs adresses mémoire ! Vous allez créer une classe Coordinate qui implémente correctement l'égalité basée sur les valeurs, ce qui lui permettra de fonctionner correctement avec les vérifications d'égalité et les collections basées sur le hachage comme Set.
Vous organiserez votre code en deux fichiers :
coordinate.dart: Créez une classeCoordinatereprésentant un point dans un espace 2D avec des champsfinal int xetfinal int y. Surchargez à la fois l'opérateur==ethashCodeafin que deux coordonnées ayant les mêmes valeurs x et y soient considérées comme égales. UtilisezObject.hash()pour générer le code de hachage à partir des deux champs.main.dart: Importez votre fichier de coordonnées et démontrez comment l'égalité basée sur les valeurs modifie le comportement de comparaison des objets :- Créez deux objets
Coordinatedistincts, tous deux avec x :5et y :10 - Affichez s'ils sont égaux en utilisant
== - Affichez s'ils sont identiques (même instance) en utilisant
identical() - Créez un
Set<Coordinate>et ajoutez les deux coordonnées à celui-ci - Affichez la longueur de l'ensemble (elle devrait être 1 puisqu'ils sont égaux !)
- Créez une troisième coordonnée avec x :
3et y :7, ajoutez-la à l'ensemble - Affichez la longueur finale de l'ensemble
- Créez deux objets
Ce défi démontre pourquoi hashCode et == doivent toujours être surchargés ensemble. Le Set utilise les codes de hachage pour organiser les éléments, donc sans un hashCode approprié, même des objets égaux pourraient être stockés comme des doublons !
Résultat attendu :
true
false
1
2Aide-mémoire
Par défaut, deux objets en Dart sont égaux uniquement s'ils sont la même instance en mémoire, et non s'ils ont les mêmes valeurs :
var p1 = Point(3, 4);
var p2 = Point(3, 4);
print(p1 == p2); // false - instances différentes !Pour comparer des objets par leurs valeurs, surchargez à la fois l'opérateur == et hashCode. Ceux-ci doivent toujours être surchargés ensemble :
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);
}Utilisez Object.hash() pour combiner plusieurs valeurs en un seul code de hachage. Le hashCode est crucial pour les collections comme Set et Map - sans lui, les objets égaux ne fonctionneront pas correctement dans les collections basées sur le hachage.
Pour vérifier si deux objets sont la même instance (et pas seulement des valeurs égales), utilisez identical() :
print(identical(p1, p2)); // false - instances différentesEssayez vous-même
import 'coordinate.dart';
void main() {
// TODO: Créer deux objets Coordinate distincts, tous deux avec x: 5 et y: 10
// TODO: Afficher s'ils sont égaux en utilisant ==
// TODO: Afficher s'ils sont identiques (même instance) en utilisant identical()
// TODO: Créer un Set<Coordinate> et y ajouter les deux coordonnées
// TODO: Afficher la longueur de l'ensemble (devrait être 1 puisqu'ils sont égaux !)
// TODO: Créer une troisième coordonnée avec x: 3 et y: 7, l'ajouter à l'ensemble
// TODO: Afficher la longueur finale de l'ensemble
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Les bases de la POO
Fichiers externesBibliothèques et importsIntroduction à la POOClasses vs ObjetsLe mot-clé thisMéthodesVariables d'instanceBases des constructeursRécapitulatif - Calculatrice simple4Null Safety
Introduction à la Null SafetyNullable vs Non-NullableLes opérateurs ? et !Le mot-clé late et la Null SafetyLes opérateurs Null-AwareLa Null Safety dans les classesRécapitulatif - Système de profil utilisateur7Classes abstraites et Interfaces
Classes abstraitesMéthodes abstraitesInterfaces en DartInterfaces implicitesImplémentation vs ExtensionInterfaces multiplesRécapitulatif - Calculateur de formes10Collections et Génériques
Aperçu des List, Set et MapCollections Type-SafeClasses génériquesMéthodes génériquesContraintes de généricitéIterable & IteratorRécapitulatif - Stockage générique2Les constructeurs en Dart
Constructeur par défautConstructeurs nommésListes d'initialisationConstructeurs constantsConstructeurs factoryConstructeurs de redirectionRécapitulatif - Shape Builder5Encapsulation
Membres publics vs privésLa convention du préfixe _Visibilité au niveau de la bibliothèqueApprofondissement des Getters & SettersMasquage d'informationsRécapitulatif - Dossiers d'étudiants8Mixins
Introduction aux MixinsCréation de MixinsUtilisation de plusieurs MixinsLe mot-clé on dans les MixinsMixin vs HéritageMixin vs InterfaceRécapitulatif - Système Animal11Méthodes spéciales
Redéfinition de toString()Redéfinition de hashCode & ==Interface ComparableMéthode call()Redéfinition de noSuchMethodRécapitulatif - Collection personnalisée14Patrons de conception Partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron ObservateurPatron Stratégie3Propriétés de classe
Membres d'instance vs statiquesChamps Final & ConstVariables LateMéthodes et champs statiquesGetters et SettersRécapitulatif - Gestionnaire de compte bancaire6Héritage
Bases de l'héritageLe mot-clé superRedéfinition de méthodeL'annotation @overrideLe mot-clé final pour les classesConstructeurs et héritageRécapitulatif - Hiérarchie des employés9Polymorphisme
Bases du polymorphismePolymorphisme via les interfacesVérification de type à l'exécutionLes opérateurs is & asMot-clé covariantRécapitulatif - Processeur de paiement12POO Asynchrone
Futures & async/awaitBases des StreamsStream ControllersConstructeurs asynchronesL'asynchrone dans les méthodes de classeRécapitulatif - Data Fetcher15Patrons de conception Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode ModèlePatron ÉtatPatron CompositePatron Repository