Comparaison d'objets Java avec equals () et hashcode ()

Dans ce Java Challenger, vous apprendrez comment equals()et hashcode()combiner pour rendre les comparaisons d'objets efficaces et faciles dans vos programmes Java. En termes simples, ces méthodes fonctionnent ensemble pour vérifier si deux objets ont les mêmes valeurs.  

Sans equals()et hashcode()nous aurions à créer de très grandes " if" comparaisons, en comparant chaque champ d'un objet. Cela rendrait le code vraiment déroutant et difficile à lire. Ensemble, ces deux méthodes nous aident à créer un code plus flexible et cohérent.

Obtenez le code source de Java Challengers.

Remplacer equals () et hashcode () en Java

Le remplacement de méthode est une technique dans laquelle le comportement de la classe ou de l'interface parente est réécrit (remplacé) dans la sous-classe afin de tirer parti du polymorphisme. Chaque Objecten Java inclut une méthode equals()et une hashcode(), mais elles doivent être remplacées pour fonctionner correctement.

Pour comprendre comment le remplacement fonctionne avec equals()et   hashcode(), nous pouvons étudier leur implémentation dans les classes Java principales. Voici la equals()méthode de la Objectclasse. La méthode vérifie si l'instance actuelle est la même que celle passée précédemment Object.

 public boolean equals(Object obj) { return (this == obj); } 

Lorsque la hashcode()méthode n'est pas remplacée, la méthode par défaut de la Objectclasse sera appelée. C'est une méthode native , ce qui signifie qu'elle sera exécutée dans un autre langage comme C, et renverra du code concernant l'adresse mémoire de l'objet. (Il n'est pas si important de savoir exactement comment cette méthode fonctionne, sauf si vous écrivez du code JDK.)

 @HotSpotIntrinsicCandidate public native int hashCode(); 

Lorsque les méthodes equals()et hashcode()ne sont pas remplacées, vous verrez les méthodes ci-dessus invoquées à la place. Dans ce cas, les méthodes ne remplissent pas l'objectif réel de equals()et hashcode(), qui est de vérifier si deux objets ou plus ont les mêmes valeurs.

En règle générale, lorsque vous remplacez, equals()vous devez également remplacer hashcode().

Comparaison d'objets avec égaux ()

Nous utilisons la equals()méthode pour comparer des objets en Java. Afin de déterminer si deux objets sont identiques, equals()compare les valeurs des attributs des objets:

 public class EqualsAndHashCodeExample { public static void main(String... equalsExplanation) { System.out.println(new Simpson("Homer", 35, 120) .equals(new Simpson("Homer",35,120))); System.out.println(new Simpson("Bart", 10, 120) .equals(new Simpson("El Barto", 10, 45))); System.out.println(new Simpson("Lisa", 54, 60) .equals(new Object())); } static class Simpson { private String name; private int age; private int weight; public Simpson(String name, int age, int weight) { this.name = name; this.age = age; this.weight = weight; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Simpson simpson = (Simpson) o; return age == simpson.age && weight == simpson.weight && name.equals(simpson.name); } } } 

Dans la première comparaison, equals()compare l'instance d'objet actuelle avec l'objet qui a été transmis. Si les deux objets ont les mêmes valeurs, equals()retournera true.

Dans la deuxième comparaison, equals()vérifie si l'objet passé est nul ou s'il est typé comme une classe différente. S'il s'agit d'une classe différente, les objets ne sont pas égaux.

Enfin, equals()compare les champs des objets. Si deux objets ont les mêmes valeurs de champ, les objets sont identiques.

Analyse des comparaisons d'objets

Voyons maintenant les résultats de ces comparaisons dans notre main()méthode. Tout d'abord, nous comparons deux Simpsonobjets:

 System.out.println(new Simpson("Homer", 35, 120).equals(new Simpson("Homer", 35, 120))); 

Les objets ici sont identiques, donc le résultat sera true.

Ensuite, nous comparons à Simpsonnouveau deux objets:

 System.out.println(new Simpson("Bart", 10, 45).equals(new Simpson("El Barto", 10, 45))); 

Les objets ici sont presque identiques mais leurs noms sont différents: Bart et El Barto. Par conséquent, le résultat sera false.

Enfin, comparons un Simpsonobjet et une instance de la classe Object:

 System.out.println(new Simpson("Lisa", 54, 60).equals(new Object())); 

Dans ce cas, le résultat sera falseque les types de classe sont différents.

égale () par rapport à ==

À première vue, l' ==opérateur et la equals()méthode peuvent sembler faire la même chose, mais en réalité, ils fonctionnent différemment. L' ==opérateur compare si deux références d'objet pointent vers le même objet. Par exemple:

 System.out.println(homer == homer2); 

Dans la première comparaison, nous avons instancié deux Simpsoninstances différentes à l'aide de l' newopérateur. Pour cette raison, les variables homeret homer2pointeront vers différentes Objectréférences dans le tas de mémoire. Nous aurons donc falsecomme résultat.

System.out.println(homer.equals(homer2)); 

Dans la deuxième comparaison, nous remplaçons la equals()méthode. Dans ce cas, seuls les noms seront comparés. Parce que le nom des deux Simpsonobjets est «Homer», le résultat sera true.

Identification unique des objets avec hashcode ()

Nous utilisons la hashcode()méthode pour optimiser les performances lors de la comparaison d'objets. L'exécution   hashcode()renvoie un ID unique pour chaque objet de votre programme, ce qui facilite grandement la comparaison de l'état complet de l'objet.

Si le hashcode d'un objet n'est pas le même que le hashcode d'un autre objet, il n'y a aucune raison d'exécuter la equals()méthode: vous savez juste que les deux objets ne sont pas les mêmes. D'autre part, si le hashcode est le même, vous devez exécuter la equals()méthode pour déterminer si les valeurs et les champs sont identiques.

Voici un exemple pratique avec hashcode().

 public class HashcodeConcept { public static void main(String... hashcodeExample) { Simpson homer = new Simpson(1, "Homer"); Simpson bart = new Simpson(2, "Homer"); boolean isHashcodeEquals = homer.hashCode() == bart.hashCode(); if (isHashcodeEquals) { System.out.println("Should compare with equals method too."); } else { System.out.println("Should not compare with equals method because " + "the id is different, that means the objects are not equals for sure."); } } static class Simpson { int id; String name; public Simpson(int id, String name) { this.id = id; this.name = name; } @Override public boolean equals(Object o)  if (this == o) return true; if (o == null  @Override public int hashCode() { return id; } } } 

Un hashcode()qui renvoie toujours la même valeur est valide mais pas très efficace. Dans ce cas, la comparaison retournera toujours true, donc la equals()méthode sera toujours exécutée. Il n'y a pas d'amélioration des performances dans ce cas.  

Utiliser equals () et hashcode () avec des collections

L' Setinterface est responsable de s'assurer qu'aucun élément en double ne sera inséré dans une Setsous - classe. Voici quelques-unes des classes qui implémentent l' Setinterface:

  • HashSet
  • TreeSet
  • LinkedHashSet
  • CopyOnWriteArraySet

Seuls des éléments uniques peuvent être insérés dans a Set, donc si vous souhaitez ajouter un élément à la HashSetclasse (par exemple), vous devez d'abord utiliser les méthodes equals()et hashcode()pour vérifier que l'élément est unique. Si les méthodes equals()et hashcode()n'étaient pas remplacées dans ce cas, vous risqueriez d'insérer des éléments en double dans le code.

Dans le code ci-dessous, nous utilisons la addméthode pour ajouter un nouvel élément à un HashSetobjet. Avant d'ajouter le nouvel élément, HashSetvérifie si l'élément existe déjà dans la collection donnée:

 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; 

Si l'objet est le même, le nouvel élément ne sera pas inséré.

Collections de hachage

Setn'est pas la seule collection qui utilise equals()et hashcode(). HashMap, Hashtable et LinkedHashMap nécessitent également ces méthodes. En règle générale, si vous voyez une collection qui a le préfixe «Hash», vous pouvez être sûr qu'elle nécessite de remplacer les méthodes hashcode()et equals()pour que leurs fonctionnalités fonctionnent correctement.  

Consignes d'utilisation de equals () et hashcode ()

Vous ne devez exécuter une equals()méthode que pour les objets qui ont le même ID de hashcode unique. Vous ne devez pas exécuter equals()lorsque l'ID de hashcode est différent.

Tableau 1. Comparaisons de Hashcode

Si la hashcode()comparaison ... Ensuite …
renvoie vrai exécuter equals()
renvoie faux ne pas exécuter equals()

This principle is mainly used in Set or Hash collections for performance reasons.

Rules for object comparison

When a hashcode() comparison returns false, the equals() method must also return false. If the hashcode is different, then the objects are definitely not equal.

Table 2. Object comparison with hashcode()

When the hashcode comparison returns ... The equals() method should return ...
true true or false
false false

When the equals() method returns true, it means that the objects are equal in all values and attributes. In this case,  the hashcode comparison must be true as well.

Table 3. Object comparison with equals()

When the equals() method returns ... The hashcode() method should return ...
true true
false true or false

Take the equals() and hashcode() challenge!

It’s time to test your skills with the equals() and hashcode() methods.  Your goal in this challenge is to figure out the output of the two equals() method comparisons and guess the size of the Set collection.

To start, study the following code carefully:

 public class EqualsHashCodeChallenge { public static void main(String... doYourBest) { System.out.println(new Simpson("Bart").equals(new Simpson("Bart"))); Simpson overriddenHomer = new Simpson("Homer") { public int hashCode() { return (43 + 777) + 1; } }; System.out.println(new Simpson("Homer").equals(overriddenHomer)); Set set = new HashSet(Set.of(new Simpson("Homer"), new Simpson("Marge"))); set.add(new Simpson("Homer")); set.add(overriddenHomer); System.out.println(set.size()); } static class Simpson { String name; Simpson(String name) { this.name = name; } @Override public boolean equals(Object obj) { Simpson otherSimpson = (Simpson) obj; return this.name.equals(otherSimpson.name) && this.hashCode() == otherSimpson.hashCode(); } @Override public int hashCode() { return (43 + 777); } } } 

Remember, analyze the code first, guess the result, and then run the code. Your goal is to improve your skill with code analysis and absorb core Java concepts to make your code more powerful. Choose your answer before checking the correct answer below.

 A) true true 4 B) true false 3 C) true false 2 D) false true 3 

What just happened? Understanding equals() and hashcode()

In the first equals() method comparison, the result is true because the state of the object is exactly the same and the hashcode() method returns the same value for both objects.

In the second equals() method comparison, the hashcode() method is being overridden for the overridenHomer variable. The name is “Homer” for both Simpson objects, but the hashcode() method returns a different value for overriddenHomer. In this case, the final result from the the equals() method will be false because the method contains a comparison with the hashcode.

You might notice that the size of the collection is set to hold three Simpson objects. Let’s check this in a detailed way.

The first object in the set will be will be inserted normally:

 new Simpson("Homer"); 

The next object will be inserted normally, as well, because it holds a different value from the previous object:

 new Simpson("Marge"); 

Finally,  the following Simpson object has the same value as the first object. In this case the object won’t be inserted:

 set.add(new Simpson("Homer")); 

Comme nous le savons, l' overridenHomerobjet utilise une valeur de hashcode différente de l' Simpson(“Homer”)instanciation normale . Pour cette raison, cet élément sera inséré dans la collection:

 overriddenHomer; 

Clé de réponse

La réponse à ce challenger Java est B . Le résultat serait:

 true false 3 

Défi vidéo! Débogage equals () et hashcode ()

Le débogage est l'un des moyens les plus simples d'absorber pleinement les concepts de programmation tout en améliorant votre code. Dans cette vidéo, vous pouvez suivre pendant que je débogue et explique le Java equals()et le hashcode()défi.