La méthode equals() détermine si deux objets sont "égaux". Par défaut, elle compare les références (c'est-à-dire ==), mais souvent les classes (par exemple, les entités, les objets de valeur) requièrent une comparaison logique basée sur les données.
Quand l'override :
Exigences :
Exemple :
public class Person { private String email; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return Objects.equals(email, person.email); } @Override public int hashCode() { return Objects.hash(email); } }
Si deux objets sont égaux selon equals(), leur hashCode() doit-il toujours être identique ?
Réponse : Oui ! C'est une exigence des contrats Java. Mais l'inverse n'est pas vrai : deux objets avec le même hashCode peuvent ne pas être égaux selon equals() — des collisions peuvent se produire pour différents objets.
Exemple d'erreur :
person1.equals(person2); // vrai person1.hashCode() != person2.hashCode(); // Erreur!
Histoire
Dans une application d'entreprise, l'entité Utilisateur a été ajoutée à un HashSet. Equals a été override, hashCode ne l'a pas été. Après modification des champs affectant equals, le HashSet a "perdu" cet objet : une tentative de recherche par méthode contains retournait false, même pour les mêmes données.
Histoire
Dans un projet IoT, les entités étaient temporairement comparées uniquement par id, puis la logique a été changée pour equals en tenant compte du nom. HashMap a commencé à se comporter de manière imprévisible, des duplicatas sont apparus lors de la mise à jour des clés — le contrat equals/hashCode a été violé à cause du mélange des versions d'implémentation.
Histoire
Lors de l'écriture d'une API pour comparer des commandes, deux classes différentes ont implémenté leur propre equals, l'une appelait getClass(), l'autre instanceof. Cela a conduit à une comparaison asymétrique des commandes et à des bugs lors de l'utilisation de collections et de la logique métier.