web-dev-qa-db-fra.com

Pourquoi dois-je remplacer les méthodes equals et hashCode en Java?

Récemment, j'ai lu ceci Developer Works Document

Le document a pour but de définir les fonctions hashCode() et equals() de manière efficace et correcte, mais je ne suis pas en mesure de comprendre pourquoi nous devons remplacer ces deux méthodes. 

Comment puis-je prendre la décision de mettre en œuvre ces méthodes efficacement?

311
Shashi

Joshua Bloch dit sur Effective Java

Vous devez surcharger hashCode () dans chaque classe qui annule equals (). Si vous ne le faites pas, cela entraînera une violation du contrat général pour Object.hashCode (), ce qui empêchera votre classe de fonctionner correctement avec toutes les collections basées sur un hachage, y compris HashMap, HashSet et Hashtable.

Essayons de le comprendre avec un exemple de ce qui se produirait si nous surchargions equals() sans surcharger hashCode() et essayions d'utiliser une variable Map.

Disons que nous avons une classe comme celle-ci et que deux objets de MyClass sont égaux si leur importantField est égale (avec hashCode() et equals() générés par Eclipse)

public class MyClass {

    private final String importantField;
    private final String anotherField;

    public MyClass(final String equalField, final String anotherField) {
        this.importantField = equalField;
        this.anotherField = anotherField;
    }

    public String getEqualField() {
        return importantField;
    }

    public String getAnotherField() {
        return anotherField;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((importantField == null) ? 0 : importantField.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final MyClass other = (MyClass) obj;
        if (importantField == null) {
            if (other.importantField != null)
                return false;
        } else if (!importantField.equals(other.importantField))
            return false;
        return true;
    }

}

Ne remplace que equals

Si seulement equals est remplacé, alors, lorsque vous appelez myMap.put(first,someValue), un hachage est créé dans un compartiment et lorsque vous appelez myMap.put(second,someOtherValue), il est répercuté sur un autre compartiment (car ils ont une hashCode différente). Ainsi, bien qu'ils soient égaux, comme ils ne partagent pas le même seau, la carte ne peut pas le réaliser et les deux restent dans la carte.


Bien qu'il ne soit pas nécessaire de remplacer equals() si nous substituons hashCode(), voyons ce qui se produirait dans ce cas particulier où nous savons que deux objets de MyClass sont égaux si leur importantField est égal mais nous ne remplaçons pas equals().

Ne remplace que hashCode

Imaginez que vous avez ceci

MyClass first = new MyClass("a","first");
MyClass second = new MyClass("a","second");

Si vous ne remplacez que hashCode, alors, lorsque vous appelez myMap.put(first,someValue), il commence par calculer, calcule sa hashCode et la stocke dans un compartiment donné. Ensuite, lorsque vous appelez myMap.put(second,someOtherValue), il convient de remplacer le premier par le suivant, conformément à la Documentation de la carte car ils sont égaux (selon les besoins de l’entreprise).

Mais le problème est que l’égalité n’a pas été redéfinie. Ainsi, lorsque la carte hache la variable second et effectue une itération dans le compartiment, il suffit de rechercher un objet k tel que second.equals(k) soit vrai, il n’en trouvera pas car second.equals(first) sera false.

J'espère que c'était clair

460
Lombo

Les collections telles que HashMap et HashSet utilisent un hashcode valeur d'un objet pour déterminer comment il doit être stocké dans une collection, et le hashcode est utilisé à nouveau pour localiser l'objet dans sa collection .

La récupération du hachage est un processus en deux étapes:

  1. Trouver le bon seau (en utilisant hashCode())
  2. Recherchez le bon élément dans le compartiment (en utilisant equals())

Voici un petit exemple expliquant pourquoi nous devrions remplacer equals() et hashcode().

Considérons une classe Employee qui a deux champs: age et name.

public class Employee {

    String name;
    int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;
        if (!(obj instanceof Employee))
            return false;
        Employee employee = (Employee) obj;
        return employee.getAge() == this.getAge()
                && employee.getName() == this.getName();
    }

    // commented    
    /*  @Override
        public int hashCode() {
            int result=17;
            result=31*result+age;
            result=31*result+(name!=null ? name.hashCode():0);
            return result;
        }
     */
}

Créez maintenant une classe, insérez un objet Employee dans une HashSet et testez si cet objet est présent ou non.

public class ClientTest {
    public static void main(String[] args) {
        Employee employee = new Employee("rajeev", 24);
        Employee employee1 = new Employee("rajeev", 25);
        Employee employee2 = new Employee("rajeev", 24);

        HashSet<Employee> employees = new HashSet<Employee>();
        employees.add(employee);
        System.out.println(employees.contains(employee2));
        System.out.println("employee.hashCode():  " + employee.hashCode()
        + "  employee2.hashCode():" + employee2.hashCode());
    }
}

Il imprimera ce qui suit:

false
employee.hashCode():  321755204  employee2.hashCode():375890482

Maintenant décommentez la méthode hashcode(), exécutez la même chose et le résultat serait: 

true
employee.hashCode():  -938387308  employee2.hashCode():-938387308

Vous pouvez maintenant voir pourquoi, si deux objets sont considérés égaux, leur hashcode s doit également être égal à? Sinon, vous ne pourrez plus jamais trouver l’objet car la valeur par défaut hashcode méthode dans la classe Object génère presque toujours un numéro unique Pour chaque objet, même si la méthode equals() est remplacée dans de telle sorte que deux objets ou plus soient considérés égaux. Peu importe l’égalité des objets si Leur hashcode s ne reflète pas cela. Encore une fois: si deux objets sont égaux, leur hashcode s doit également l'être.

164
rajeev pani..

Vous devez surcharger hashCode () dans chaque classe qui annule equals (). Échec cela entraînerait une violation de le contrat général pour Object.hashCode (), ce qui empêchera votre classe de fonctionner correctement en conjonction avec tous collections, y compris HashMap, HashSet et Hashtable.


from Effective Java, de Joshua Bloch

En définissant equals() et hashCode() de manière cohérente, vous pouvez améliorer la convivialité de vos classes en tant que clés dans les collections basées sur un hachage. Comme l'explique la documentation de l'API pour hashCode: "Cette méthode est prise en charge au profit des hashtables telles que celles fournies par Java.util.Hashtable." 

La meilleure réponse à votre question sur la façon de mettre en œuvre efficacement ces méthodes vous suggère de lire le chapitre 3 de Effective Java .

48
JuanZe

En termes simples, la méthode equals de la vérification d'objet pour l'égalité des références, où deux instances de votre classe pourraient toujours être sémantiquement égales lorsque les propriétés sont égales. Ceci est par exemple important lorsque vous placez vos objets dans un conteneur qui utilise equals et hashcode, comme HashMap et Set . Disons que nous avons une classe comme:

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }
}

Nous créons deux instances avec le même id:

Foo a = new Foo("id", "something");
Foo b = new Foo("id", "something else");

Sans égaux, nous obtenons:

  • a.equals (b) est false car il s'agit de deux instances différentes
  • a.equals (a) est vrai puisqu'il s'agit de la même instance
  • b.equals (b) est vrai puisqu'il s'agit de la même instance

Correct? Eh bien peut-être, si c'est ce que vous voulez. Mais disons que nous voulons que les objets avec le même identifiant soient le même objet, qu'il s'agisse ou non de deux instances différentes. Nous remplaçons les égaux (et hashcode):

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof Foo) {
            return ((Foo)other).id.equals(this.id);   
        }
    }

    @Override
    public int hashCode() {
        return this.id.hashCode();
    }
}

Pour implémenter equals et hashcode, je peux vous recommander d’utiliser les méthodes d’aide de Guava

19
crunchdog

L'identité n'est pas l'égalité.

  • équivaut à l'identité de test de l'opérateur ==.
  • La méthode equals(Object obj) compare le test d’égalité (c’est-à-dire que nous devons dire l’égalité en remplaçant la méthode)

Pourquoi dois-je remplacer les méthodes equals et hashCode en Java? 

Nous devons d'abord comprendre l'utilisation de la méthode des égaux.

Afin d'identifier les différences entre deux objets, nous devons redéfinir la méthode equals. 

Par exemple:

Customer customer1=new Customer("peter");
Customer customer2=customer1;
customer1.equals(customer2); // returns true by JVM. i.e. both are refering same Object
------------------------------
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
customer1.equals(customer2); //return false by JVM i.e. we have two different peter customers.

------------------------------
Now I have overriden Customer class equals method as follows:
 @Override
    public boolean equals(Object obj) {
        if (this == obj)   // it checks references
            return true;
        if (obj == null) // checks null
            return false;
        if (getClass() != obj.getClass()) // both object are instances of same class or not
            return false;
        Customer other = (Customer) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name)) // it again using bulit in String object equals to identify the difference 
            return false;
        return true; 
    }
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
Insteady identify the Object equality by JVM, we can do it by overring equals method.
customer1.equals(customer2);  // returns true by our own logic

Maintenant, la méthode hashCode peut comprendre facilement.

hashCode produit un entier pour stocker un objet dans des structures de données telles que HashMap , HashSet .

Supposons que nous ayons surchargé la méthode égale de Customer comme ci-dessus, 

customer1.equals(customer2);  // returns true by our own logic

Tout en travaillant avec la structure de données lorsque nous stockons des objets dans des compartiments (le compartiment est un nom de fantaisie pour le dossier). Si nous utilisons la technique de hachage intégrée, elle génère deux codes de hachage différents pour les deux clients précédents. Nous stockons donc le même objet identique à deux endroits différents. Pour éviter ce genre de problème, nous devons remplacer la méthode hashCode également sur la base des principes suivants. 

  • les instances non égales peuvent avoir le même hashcode.
  • des instances égales devraient renvoyer le même hashcode.
15
Premraj

Ok, laissez-moi vous expliquer le concept avec des mots très simples.

D'abord, dans une perspective plus large, nous avons des collections, et hashmap est l'une des structures de données dans les collections.

Pour comprendre pourquoi nous devons redéfinir les méthodes equals et hashcode, nous devons d’abord comprendre ce qui est hashmap et ce qu’il fait.

Un hashmap est une structure de données qui stocke des paires de valeurs de données clés sous forme de tableau. Disons un [], où chaque élément de 'a' est une paire clé-valeur.

De plus, chaque index du tableau ci-dessus peut être une liste chaînée, ce qui donne plusieurs valeurs à un index.

Maintenant, pourquoi utilise-t-on une table de hachage? Si nous devons chercher dans un grand tableau, puis chercher dans chacun d’eux si leur efficacité est réduite, c’est pourquoi la technique de hachage nous permet de pré-traiter le tableau avec une certaine logique et de regrouper les éléments sur cette logique à savoir le hachage

exemple: nous avons le tableau 1,2,3,4,5,6,7,8,9,10,11 et nous appliquons une fonction de hachage mod 10 afin que 1,11 soit regroupé. Donc, si nous devions rechercher 11 dans le tableau précédent, nous devrions itérer le tableau complet, mais lorsque nous le regroupons, nous limitons notre étendue d'itération, ce qui améliore la vitesse. Cette structure de données utilisée pour stocker toutes les informations ci-dessus peut être considérée comme un tableau 2D pour plus de simplicité.

Maintenant, mis à part le hashmap ci-dessus, il est également indiqué qu'il n'y ajoutera pas de doublons. Et c’est la raison principale pour laquelle nous devons remplacer les égaux et le hashcode

Donc, quand on dit que cela explique le fonctionnement interne de hashmap, nous devons trouver quelles méthodes a le hashmap et comment il suit les règles ci-dessus que j'ai expliquées ci-dessus

la méthode hashmap est donc appelée put (K, V) et, conformément à hashmap, elle doit suivre les règles ci-dessus pour distribuer efficacement le tableau et ne pas ajouter de doublons.

donc, ce qui est fait, c'est qu'il va d'abord générer le hashcode pour la clé donnée afin de décider quel index la valeur doit entrer. Si rien n'est présent à cet index, la nouvelle valeur sera ajoutée là-bas, si quelque chose est déjà présent là-bas alors la nouvelle valeur devrait être ajoutée après la fin de la liste liée à cet index. mais rappelez-vous, aucun doublon ne doit être ajouté selon le comportement souhaité du hashmap. alors disons que vous avez deux objets Integer aa = 11, bb = 11 . comme chaque objet dérivé de la classe d'objet, l'implémentation par défaut pour comparer deux objets est qu'il compare la référence et non les valeurs à l'intérieur de l'objet. Ainsi, dans le cas ci-dessus, le test d’égalité échouera, même s’il est sémantiquement égal, et la possibilité que deux objets ayant le même hashcode et les mêmes valeurs existent, créant ainsi des doublons. Si nous ignorons alors nous pourrions éviter d’ajouter des doublons . Vous pouvez également vous référer à Travail détaillé

import Java.util.HashMap;


public class Employee {

String name;
String mobile;
public Employee(String name,String mobile) {
    this.name=name;
    this.mobile=mobile;
}

@Override
public int hashCode() {
    System.out.println("calling hascode method of Employee");
    String str=this.name;
    Integer sum=0;
    for(int i=0;i<str.length();i++){
        sum=sum+str.charAt(i);
    }
    return sum;

}
@Override
public boolean equals(Object obj) {
    // TODO Auto-generated method stub
    System.out.println("calling equals method of Employee");
    Employee emp=(Employee)obj;
    if(this.mobile.equalsIgnoreCase(emp.mobile)){

        System.out.println("returning true");
        return true;
    }else{
        System.out.println("returning false");
        return false;
    }


}

public static void main(String[] args) {
    // TODO Auto-generated method stub

    Employee emp=new Employee("abc", "hhh");
    Employee emp2=new Employee("abc", "hhh");
    HashMap<Employee, Employee> h=new HashMap<>();
    //for (int i=0;i<5;i++){
        h.put(emp, emp);
        h.put(emp2, emp2);

    //}

    System.out.println("----------------");
    System.out.println("size of hashmap: "+h.size());


}

}
12
Chetan

hashCode():

Si vous ne remplacez que la méthode hash-code, rien ne se passera. Parce qu'il renvoie toujours new hashCode pour chaque objet en tant que classe Object.

equals():

Si vous ne substituez que la méthode égale, a.equals(b) est true, cela signifie que hashCode de a et b doit être identique mais ne doit pas se produire. Parce que vous n'avez pas remplacé la méthode hashCode.

Remarque: La méthode hashCode() de la classe Object renvoie toujours le nouveau hashCode pour chaque objet.

Ainsi, lorsque vous devez utiliser votre objet dans la collection basée sur le hachage, vous devez redéfinir les noms equals() et hashCode().

10
Rinkal Gupta

Afin d'utiliser nos propres objets de classe comme clés dans des collections telles que HashMap, Hashtable, etc., nous devons remplacer les deux méthodes (hashCode () et equals ()) en prenant conscience du fonctionnement interne de la collection. Sinon, cela conduit à des résultats erronés auxquels nous ne sommes pas attendus.

6
Prashanth

Parce que si vous ne les remplacez pas, vous utiliserez l'implémentation par défaut dans Object.

Étant donné que l'égalité d'instance et les valeurs de code has nécessitent généralement la connaissance de la composition d'un objet, elles devront généralement être redéfinies dans votre classe pour avoir une signification concrète.

6
PaulJWilliams
class A {
    int i;
    // Hashing Algorithm
    if even number return 0 else return 1
    // Equals Algorithm,
    if i = this.i return true else false
}
  • put ('clé', 'valeur') calculera la valeur de hachage en utilisant hashCode() pour déterminer le bucket et en utilisant la méthode equals() pour déterminer si la valeur est déjà présente dans le seau. Sinon, il sera ajouté sinon il sera remplacé par la valeur actuelle
  • get ('key') utilisera hashCode() pour trouver l'entrée (compartiment) en premier et equals() pour trouver la valeur dans l'entrée

si les deux sont remplacés,

Carte <A

Map.Entry 1 --> 1,3,5,...
Map.Entry 2 --> 2,4,6,...

si égal n'est pas remplacé

Carte <A

Map.Entry 1 --> 1,3,5,...,1,3,5,... // Duplicate values as equals not overridden
Map.Entry 2 --> 2,4,6,...,2,4,..

Si hashCode n'est pas remplacé

Carte <A

Map.Entry 1 --> 1
Map.Entry 2 --> 2
Map.Entry 3 --> 3
Map.Entry 4 --> 1
Map.Entry 5 --> 2
Map.Entry 6 --> 3 // Same values are Stored in different hasCodes violates Contract 1
So on...

HashCode Equal Contract

  1. Deux clés égales selon la même méthode devraient générer le même hashCode
  2. Deux clés générant le même hashCode n'ont pas besoin d'être égales (dans l'exemple ci-dessus, tous les nombres pairs génèrent le même hash Code)
5
bharanitharan

Java met une règle qui 

"Si deux objets sont égaux à l'aide de la méthode Object class equals, la méthode hashcode devrait donner la même valeur pour ces deux objets."

Donc, si dans notre classe nous substituons equals() nous devrions surcharger la méthode hashcode() également pour suivre cette règle . Les deux méthodes equals() et hashcode() sont utilisées dans Hashtable, par exemple, pour stocker des valeurs sous forme de paires clé-valeur. Si nous remplaçons l'un et pas l'autre, il est possible que la variable Hashtable ne fonctionne pas comme nous le souhaitons, si nous utilisons un tel objet comme clé.

5
Ritesh Kaushik

Considérez la collection de balles dans un seau tout en couleur noire. Votre travail consiste à colorer ces balles comme suit et à les utiliser pour le jeu approprié,

Pour le tennis - jaune, rouge . Pour le cricket - blanc

Maintenant, le seau a des balles en trois couleurs: jaune, rouge et blanc. Et que maintenant vous avez fait la coloration Seulement vous savez quelle couleur est pour quel jeu.

Colorer les balles - Hashing . Choisir la balle pour le jeu - Equals.

Si vous faites la coloration et que quelqu'un choisit la balle pour le cricket ou le tennis, cela ne gêne pas la couleur !!!

4
bharanitharan

Je cherchais l'explication suivante: "Si vous ne remplacez que hashCode, l'appelez myMap.put(first,someValue) il prend d'abord, calcule son hashCode et le stocke dans un compartiment donné. Ensuite, lorsque vous appelez myMap.put(first,someOtherValue), il doit remplacer en premier par second selon la documentation cartographique sont égaux (selon notre définition). " :

Je pense que la 2ème fois que nous ajoutons dans myMap, alors cela devrait être le 'deuxième' objet comme myMap.put(second,someOtherValue)

4
Narinder

Méthodes Equals et Hashcode en Java

Ce sont des méthodes de la classe Java.lang.Object, qui est la super-classe de toutes les classes (classes personnalisées et autres définies dans l'API Java).

La mise en oeuvre:

public boolean equals (Object obj)

public int hashCode ()

 enter image description here

public boolean equals (Object obj)

Cette méthode vérifie simplement si deux références d'objet x et y se rapportent au même objet. c'est-à-dire qu'il vérifie si x == y.

C'est réflexif: pour toute valeur de référence x, x.equals (x) doit renvoyer true.

Il est symétrique: pour toutes les valeurs de référence x et y, x.equals (y) doit renvoyer true si et seulement si y.equals (x) renvoie true.

Il est transitif: pour toutes les valeurs de référence x, y et z, si x.equals (y) renvoie true et que y.equals (z) renvoie true, alors x.equals (z) doit renvoyer true.

Il est cohérent: pour toutes les valeurs de référence x et y, les invocations multiples de x.equals (y) retournent systématiquement true ou systématiquement false, à condition qu'aucune des informations utilisées dans les comparaisons égales de l'objet ne soit modifiée.

Pour toute valeur de référence non nulle x, x.equals (null) doit renvoyer faux.

public int hashCode ()

Cette méthode retourne la valeur de code de hachage pour l'objet sur lequel cette méthode est appelée. Cette méthode retourne la valeur du code de hachage sous forme d'entier et est prise en charge pour l'avantage des classes de collection basées sur le hachage telles que Hashtable, HashMap, HashSet, etc. Cette méthode doit être remplacée dans chaque classe remplaçant la méthode equals.

Le contrat général de hashCode est:

Chaque fois qu'elle est invoquée plusieurs fois sur le même objet lors de l'exécution d'une application Java, la méthode hashCode doit systématiquement renvoyer le même entier, à condition qu'aucune information utilisée dans les comparaisons égales de l'objet ne soit modifiée. 

Cet entier n'a pas besoin de rester cohérent d'une exécution d'une application à une autre exécution de la même application.

Si deux objets sont égaux selon la méthode equals (Object), l'appel de la méthode hashCode sur chacun des deux objets doit produire le même résultat entier.

Il n'est pas nécessaire que si deux objets soient inégaux selon la méthode equals (Java.lang.Object), l'appel de la méthode hashCode sur chacun des deux objets doit produire des résultats entiers distincts. Cependant, le programmeur doit savoir que la production de résultats entiers distincts pour des objets inégaux peut améliorer les performances des hashtables.

Les objets identiques doivent produire le même code de hachage tant qu'ils sont égaux, cependant, des objets inégaux ne doivent pas nécessairement produire des codes de hachage distincts.

Ressources: 

JavaRanch

Image

3
Virtual

Les méthodes equals et hashcode sont définis dans la classe d'objet. Par défaut, si la méthode equals renvoie true, le système ira plus loin et vérifiera la valeur du code de hachage. Si le code de hachage des 2 objets est également identique, alors les objets seront considérés comme identiques. Ainsi, si vous ne substituez que la méthode equals, alors même si la méthode equals remplacée indique que 2 objets sont égaux, le hashcode défini par le système peut ne pas indiquer que les 2 objets sont égaux. Nous devons donc également remplacer le code de hachage.

3
Aarti

Supposons que la classe (A) regroupe deux autres (B) (C) et que vous ayez besoin de stocker des instances de (A) dans une table de hachage. L'implémentation par défaut permet uniquement de distinguer les instances, mais pas avec (B) et (C). Donc, deux instances de A pourraient être égales, mais défaut ne vous permettrait pas de les comparer correctement. 

3
Dewfy

C'est utile lorsque vous utilisez Objets valeur . Ce qui suit est un extrait du Portland Pattern Repository :

Des exemples d'objets de valeur sont des choses comme des nombres, des dates, de l'argent et des cordes. Habituellement, ils sont petits objets qui sont utilisés assez largement . Leur identité est basée sur leur état plutôt que sur leur identité d'objet . De cette façon, vous pouvez avoir plusieurs copies du même objet de valeur conceptuelle.

Donc, je peux avoir plusieurs copies d'un objet qui représente la date du 16 janvier 1998. Chacune de ces copies sera égale à l'autre. Pour un petit objet tel que celui-ci, il est souvent plus facile de créer de nouveaux et de déplacer autour d'eux plutôt que de compter sur un objet unique pour représenter la date.

Un objet de valeur doit toujours remplacer .equals () en Java (ou = en Smalltalk) . (N'oubliez pas de remplacer .hashCode () par Well.)

3
Ionuț G. Stan

La classe String et les classes wrapper ont une implémentation différente des méthodes equals() et hashCode() par rapport à la classe Object. La méthode equals () de la classe Object compare les références des objets, pas leur contenu. La méthode hashCode () de la classe Object renvoie un hashcode distinct pour chaque objet, que le contenu soit identique.

Cela pose problème lorsque vous utilisez Collection de cartes et que la clé est de type Persistent, de type StringBuffer/Builder. Comme ils ne remplacent pas equals () et hashCode (), contrairement à la classe String, equals () renverra false lorsque vous comparez deux objets différents, même s'ils ont le même contenu. HashMap stockera les mêmes clés de contenu. Stocker les mêmes clés de contenu signifie qu'il enfreint la règle de Map car Map n'autorise pas la duplication de clés . Par conséquent, vous substituez les méthodes equals () ainsi que hashCode () dans votre classe et fournissez l'implémentation (l'IDE peut générer ces méthodes) ) de sorte qu'ils fonctionnent de la même manière que equals () et hashCode () de String et empêchent les mêmes clés de contenu. 

Vous devez redéfinir la méthode hashCode () avec equals (), car equals () fonctionne selon hashcode. 

De plus, surcharger la méthode hashCode () avec equals () aide à préserver le contrat equals () - hashCode (): "Si deux objets sont égaux, ils doivent avoir le même code de hachage."

Quand avez-vous besoin d'écrire une implémentation personnalisée pour hashCode ()?

Comme nous le savons, le fonctionnement interne de HashMap est basé sur le principe de hachage. Il y a certains compartiments où les ensembles d'entrées sont stockés. Vous personnalisez l'implémentation hashCode () en fonction de vos besoins afin que les mêmes objets de catégorie puissent être stockés dans le même index. lorsque vous stockez les valeurs dans la collection Map à l'aide de put(k,v)method, l'implémentation interne de put () est la suivante:

put(k, v){
hash(k);
index=hash & (n-1);
}

Cela signifie qu'il génère un index et que l'index est généré sur la base du hashcode d'un objet clé particulier. Assurez-vous donc que cette méthode génère un hashcode en fonction de vos besoins, car les mêmes ensembles d'entrées hashcode seront stockés dans le même compartiment ou index. 

C'est tout!

2
Arun Raaj

1) L'erreur commune est illustrée dans l'exemple ci-dessous.

public class Car {

    private String color;

    public Car(String color) {
        this.color = color;
    }

    public boolean equals(Object obj) {
        if(obj==null) return false;
        if (!(obj instanceof Car))
            return false;   
        if (obj == this)
            return true;
        return this.color.equals(((Car) obj).color);
    }

    public static void main(String[] args) {
        Car a1 = new Car("green");
        Car a2 = new Car("red");

        //hashMap stores Car type and its quantity
        HashMap<Car, Integer> m = new HashMap<Car, Integer>();
        m.put(a1, 10);
        m.put(a2, 20);
        System.out.println(m.get(new Car("green")));
    }
}

la voiture verte est introuvable

2. Problème causé par hashCode ()

Le problème est dû à la méthode non remplacée hashCode(). Le contrat entre equals() et hashCode() est le suivant:

  1. Si deux objets sont égaux, alors ils doivent avoir le même code de hachage.
  2. Si deux objets ont le même code de hachage, ils peuvent être égaux ou non.

    public int hashCode(){  
      return this.color.hashCode(); 
    }
    
2
Neeraj Gahlawat

Dans l'exemple ci-dessous, si vous commentez le remplacement pour Equals ou hashcode dans la classe Person, ce code ne pourra pas rechercher la commande de Tom. L'utilisation de l'implémentation par défaut de hashcode peut entraîner des erreurs dans les recherches de hashtable.

Ce que j'ai ci-dessous est un code simplifié qui établit l'ordre des personnes par personne. La personne est utilisée comme clé dans la table de hachage.

public class Person {
    String name;
    int age;
    String socialSecurityNumber;

    public Person(String name, int age, String socialSecurityNumber) {
        this.name = name;
        this.age = age;
        this.socialSecurityNumber = socialSecurityNumber;
    }

    @Override
    public boolean equals(Object p) {
        //Person is same if social security number is same

        if ((p instanceof Person) && this.socialSecurityNumber.equals(((Person) p).socialSecurityNumber)) {
            return true;
        } else {
            return false;
        }

    }

    @Override
    public int hashCode() {        //I am using a hashing function in String.Java instead of writing my own.
        return socialSecurityNumber.hashCode();
    }
}


public class Order {
    String[]  items;

    public void insertOrder(String[]  items)
    {
        this.items=items;
    }

}



import Java.util.Hashtable;

public class Main {

    public static void main(String[] args) {

       Person p1=new Person("Tom",32,"548-56-4412");
        Person p2=new Person("Jerry",60,"456-74-4125");
        Person p3=new Person("Sherry",38,"418-55-1235");

        Order order1=new Order();
        order1.insertOrder(new String[]{"mouse","car charger"});

        Order order2=new Order();
        order2.insertOrder(new String[]{"Multi vitamin"});

        Order order3=new Order();
        order3.insertOrder(new String[]{"handbag", "iPod"});

        Hashtable<Person,Order> hashtable=new Hashtable<Person,Order>();
        hashtable.put(p1,order1);
        hashtable.put(p2,order2);
        hashtable.put(p3,order3);

       //The line below will fail if Person class does not override hashCode()
       Order tomOrder= hashtable.get(new Person("Tom", 32, "548-56-4412"));
        for(String item:tomOrder.items)
        {
            System.out.println(item);
        }
    }
}
2
developer747

IMHO, c'est comme par la règle dit - Si deux objets sont égaux, alors ils devraient avoir le même hachage, c'est-à-dire, des objets égaux devraient produire des valeurs de hachage égales.

Comme indiqué ci-dessus, equals () dans Object correspond à ==, qui effectue une comparaison d'adresse. HashCode () renvoie l'adresse en entier (hachage sur l'adresse réelle), qui est à nouveau distinct pour Object distinct.

Si vous devez utiliser les objets personnalisés dans les collections basées sur le hachage, vous devez redéfinir equals () et hashCode (), par exemple Si je souhaite conserver le hachage des objets employés, si je n'utilise pas hashCode plus puissant Je peux finir par remplacer les deux objets employés différents, ce qui se produit lorsque j'utilise l'âge comme hashCode (), mais je devrais utiliser la valeur unique qui peut être l'ID d'employé.

1
Cleonjoys

La méthode hashCode() est utilisée pour obtenir un entier unique pour un objet donné. Cet entier est utilisé pour déterminer l'emplacement du compartiment, lorsque cet objet doit être stocké dans une structure de données semblable à HashTable, HashMap. Par défaut, la méthode hashCode() de Object renvoie une représentation entière de l’adresse mémoire où l’objet est stocké.

La méthode hashCode() des objets est utilisée lorsque nous les insérons dans un HashTable, HashMap ou HashSet. En savoir plus sur HashTables sur Wikipedia.org pour référence.

Pour insérer une entrée dans la structure de données de la carte, nous avons besoin à la fois de clé et de valeur. Si la clé et les valeurs sont des types de données définis par l'utilisateur, la fonction hashCode() de la clé déterminera l'emplacement de stockage interne de l'objet. Lorsqu'il est également nécessaire de rechercher l'objet sur la carte, le code de hachage de la clé déterminera où rechercher l'objet.

Le code de hachage pointe uniquement vers une certaine "zone" (ou liste, compartiment, etc.) en interne. Étant donné que différents objets de clé pourraient potentiellement avoir le même code de hachage, le code de hachage lui-même ne garantit pas que la bonne clé est trouvée. La HashTable itère ensuite cette zone (toutes les clés avec le même code de hachage) et utilise la méthode equals() de la clé pour rechercher la bonne clé. Une fois que la bonne clé est trouvée, l'objet stocké pour cette clé est renvoyé.

Ainsi, comme nous pouvons le constater, une combinaison des méthodes hashCode() et equals() est utilisée lors du stockage et lors de la recherche d'objets dans une HashTable.

REMARQUES:

  1. Utilisez toujours les mêmes attributs d'un objet pour générer les fonctions hashCode() et equals(). Comme dans notre cas, nous avons utilisé l'identifiant d'employé.

  2. equals() doit être cohérent (si les objets ne sont pas modifiés, il doit continuer à renvoyer la même valeur).

  3. Chaque fois que a.equals(b), alors a.hashCode() doit être identique à b.hashCode().

  4. Si vous en substituez un, vous devez remplacer l'autre.

http://parameshk.blogspot.in/2014/10/examples-of-comparable-comporator.html

1
Paramesh Korrakuti

Pour vous aider à vérifier les objets en double, nous avons besoin d'un égaux personnalisés et d'un hashCode.

Puisque hashcode retourne toujours un nombre, il est toujours rapide de récupérer un objet en utilisant un nombre plutôt qu'une clé alphabétique. Comment ça va faire? Supposons que nous avons créé un nouvel objet en transmettant une valeur déjà disponible dans un autre objet. Maintenant, le nouvel objet renverra la même valeur de hachage que celle d'un autre objet car la valeur transmise est la même. Une fois que la même valeur de hachage est renvoyée, JVM accédera à la même adresse mémoire à chaque fois. Si plusieurs objets sont présents pour la même valeur de hachage, la méthode equals () sera utilisée pour identifier le bon objet.

1
Tavash
public class Employee {

    private int empId;
    private String empName;

    public Employee(int empId, String empName) {
        super();
        this.empId = empId;
        this.empName = empName;
    }

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    @Override
    public String toString() {
        return "Employee [empId=" + empId + ", empName=" + empName + "]";
    }

    @Override
    public int hashCode() {
        return empId + empName.hashCode();
    }

    @Override
    public boolean equals(Object obj) {

        if (this == obj) {
            return true;
        }
        if (!(this instanceof Employee)) {
            return false;
        }
        Employee emp = (Employee) obj;
        return this.getEmpId() == emp.getEmpId() && this.getEmpName().equals(emp.getEmpName());
    }

}

Classe d'essai 

public class Test {

    public static void main(String[] args) {
        Employee emp1 = new Employee(101,"Manash");
        Employee emp2 = new Employee(101,"Manash");
        Employee emp3 = new Employee(103,"Ranjan");
        System.out.println(emp1.hashCode());
        System.out.println(emp2.hashCode());
        System.out.println(emp1.equals(emp2));
        System.out.println(emp1.equals(emp3));
    }

}

Dans Object Class, equals (Object obj) est utilisé pour comparer les comparaisons d'adresses. C'est pourquoi, lorsque vous comparez deux objets dans la classe Test, la méthode equals donne false, mais lorsque nous remplaçons hashcode (), il peut comparer le contenu et obtenir un résultat correct.

0
Manash Ranjan Dakua

Lorsque vous souhaitez stocker et récupérer votre objet personnalisé en tant que clé dans Map, vous devez toujours remplacer les valeurs equals et hashCode dans votre objet personnalisé .

Person p1 = new Person("A",23);
Person p2 = new Person("A",23);
HashMap map = new HashMap();
map.put(p1,"value 1");
map.put(p2,"value 2");

Ici, p1 & p2 considéreront comme un seul objet et la taille map sera seulement 1 parce qu'ils sont égaux.

0
Ambrish Rajput