Comment un HashMap Java gère-t-il différents objets avec le même code de hachage?


Selon ma compréhension, je pense:

  1. Il est parfaitement légal que deux objets aient le même hashcode.
  2. Si deux objets sont égaux (en utilisant la méthode equals ()), ils ont le même hashcode.
  3. Si deux objets ne sont pas égaux, ils ne peuvent pas avoir le même hashcode

Ai-je raison?

Maintenant, si je suis correct, j'ai la question suivante: Le HashMap utilise en interne le hashcode de l'objet. Donc, si deux objets peuvent avoir le même hashcode, alors comment le HashMap peut-il suivre la clé qu'il utilise?

Quelqu'un Peut m'expliquer comment le HashMap utilise en interne le hashcode de l'objet?

Author: Chris Gong, 2011-06-27

16 answers

Une hashmap fonctionne comme ceci (c'est un peu simplifié, mais il illustre le mécanisme de base):

Il a un certain nombre de "seaux" qu'il utilise pour stocker des paires clé-valeur. Chaque seau a un numéro unique-c'est ce qui identifie le seau. Lorsque vous placez une paire clé-valeur dans la carte, le hashmap examinera le code de hachage de la clé et stockera la paire dans le compartiment dont l'identifiant est le code de hachage de la clé. Par exemple: Le code de hachage de la clé est 235- > la paire est stocké dans le seau numéro 235. (À noter qu'un compartiment peut stocker plus d'une paire clé-valeur).

Lorsque vous recherchez une valeur dans le hashmap, en lui donnant une clé, il va d'abord regarder le code de hachage de la clé que vous avez donnée. Le hashmap examinera ensuite le compartiment correspondant, puis il comparera la clé que vous avez donnée avec les clés de toutes les paires du compartiment, en les comparant avec equals().

Maintenant, vous pouvez voir comment cela est très efficace pour rechercher des paires clé-valeur dans un map: par le code de hachage de la clé, le hashmap sait immédiatement dans quel compartiment regarder, de sorte qu'il n'a qu'à tester par rapport à ce qui se trouve dans ce compartiment.

En regardant le mécanisme ci-dessus, vous pouvez également voir quelles exigences sont nécessaires sur les méthodes hashCode() et equals() des clés:

  • Si deux clés sont identiques (equals() renvoie true lorsque vous les comparez), leur méthode hashCode() doit renvoyer le même nombre. Si les clés violent cela, alors les clés qui sont égales peuvent être stockées dans différents les compartiments, et le hashmap ne serait pas en mesure de trouver des paires clé-valeur (car il va regarder dans le même compartiment).

  • Si deux clés sont différentes, peu importe si leurs codes de hachage sont les mêmes ou non. Ils seront stockés dans le même compartiment si leurs codes de hachage sont les mêmes, et dans ce cas, le hashmap utilisera equals() pour les distinguer.

 297
Author: Jesper, 2013-09-05 00:16:30

Votre troisième assertion est incorrecte.

Il est parfaitement légal pour deux objets inégaux d'avoir le même code de hachage. Il est utilisé par HashMapcomme "filtre de premier passage" afin que la carte puisse rapidement trouver des entrées possibles avec la clé spécifiée. Les clés avec le même code de hachage sont ensuite testées pour l'égalité avec la clé spécifiée.

Vous ne voudriez pas une exigence selon laquelle deux objets inégaux ne pourraient pas avoir le même code de hachage, sinon cela vous limiterait à 232 les objets possibles. (Cela signifierait également que différents types ne pourraient même pas utiliser les champs d'un objet pour générer des codes de hachage, car d'autres classes pourraient générer le même hachage.)

 80
Author: Jon Skeet, 2013-08-23 13:29:11

Diagramme de structure HashMap

HashMap est un tableau de Entry objets.

Considérez HashMap comme juste un tableau d'objets.

Regardez ce qu'est ce Object:

static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        final int hash;
… 
}

Chaque objet Entry représente une paire clé-valeur. Le champ next fait référence à un autre objet Entry si un compartiment a plus d'un Entry.

Parfois, il peut arriver que les codes de hachage pour 2 objets différents soient les mêmes. Dans ce cas, deux objets seront enregistrés dans un compartiment et seront présentés comme un liste liée. Le point d'entrée est l'objet ajouté le plus récemment. Cet objet fait référence à un autre objet avec le champ next et ainsi de suite. La dernière entrée fait référence à null.

Lorsque vous créez un HashMap avec le constructeur par défaut

HashMap hashMap = new HashMap();

Le tableau est créé avec une taille 16 et un équilibre de charge par défaut de 0,75.

Ajout d'une nouvelle paire clé-valeur

  1. Calculer hashcode pour la clé
  2. Calculer la position hash % (arrayLength-1) où l'élément doit être placé (seau nombre)
  3. Si vous essayez d'ajouter une valeur avec une clé qui a déjà été enregistrée dans HashMap, la valeur est écrasée.
  4. Sinon l'élément est ajouté au compartiment.

Si le seau a déjà au moins un élément, un nouveau est ajouté et placé dans la première position du seau. Son champ next fait référence à l'ancien élément.

Suppression

  1. Calculer hashcode pour la clé donnée
  2. Calculer le nombre de seau hash % (arrayLength-1)
  3. Obtenir un référence au premier objet d'entrée dans le compartiment et au moyen de la méthode equals itérer sur toutes les entrées dans le compartiment donné. Finalement, nous trouverons le Entry correct. Si un élément souhaité n'est pas trouvé, retournez null
 57
Author: Sergii Shevchyk, 2016-07-06 20:42:39

Vous pouvez trouver d'excellentes informations à http://javarevisited.blogspot.com/2011/02/how-hashmap-works-in-java.html

Pour Résumer:

HashMap fonctionne sur le principe du hachage

Put (key, value): HashMap stocke à la fois la clé et l'objet de valeur en tant que carte.Entrée. Hashmap applique hashcode (clé) pour obtenir le compartiment. s'il y a collision ,HashMap utilise LinkedList pour stocker l'objet.

Get (key): HashMap utilise le hashcode de l'objet clé pour trouver sortir l'emplacement du compartiment, puis appeler les clés.méthode equals () pour identifier le nœud correct dans LinkedList et renvoyer l'objet valeur associé pour cette clé dans Java HashMap.

 33
Author: Abhijit Gaikwad, 2013-03-14 04:30:15

Voici une description approximative du mécanisme de HashMap, pour la version Java 8, (il pourrait être légèrement différent de Java 6).


Structures de Données

  • Table de hachage
    La valeur de hachage est calculée via hash() sur la clé, et elle décide quel compartiment de la table de hachage utiliser pour une clé donnée.
  • Liste chaînée (un seul)
    Lorsque le nombre d'éléments dans un compartiment est petit, une liste chaînée unique est utiliser.
  • Arbre rouge-noir
    Lorsque le nombre d'éléments dans un seau est grand, rouge-noir arbre est utilisé.

Les Classes (interne)

  • Map.Entry
    Représenter une seule entité dans map, l'entité clé / valeur.
  • HashMap.Node
    Version de la liste chaînée du nœud.

    , Il pourrait représenter:

    • Un seau de hachage.
      Parce qu'il a une propriété de hachage.
    • Un nœud dans une liste chaînée, (donc aussi la liste des liens) .
  • HashMap.TreeNode
    Version arborescente du nœud.

Champs (interne)

  • Node[] table
    La table de seau, (tête des listes liées).
    Si un compartiment ne contient pas d'éléments, alors il est null, ne prend donc que l'espace d'une référence.
  • Set<Map.Entry> entrySet Ensemble d'entités.
  • int size
    Nombre d'entités.
  • float loadFactor
    Indiquez à quel point la table de hachage est autorisée, avant redimensionner.
  • int threshold
    La taille suivante à laquelle redimensionner.
    Formule: threshold = capacity * loadFactor

Méthodes (interne)

  • int hash(key)
    Calculez le hachage par clé.
  • Comment mapper hash à bucket?
    Utilisez la logique suivante:

    static int hashToBucket(int tableSize, int hash) {
        return (tableSize - 1) & hash;
    }
    

À propos de la capacité

Dans la table de hachage, la capacité signifie le nombre de compartiments, elle pourrait être obtenue à partir de table.length.
Peut également être calculé via threshold et loadFactor, donc pas besoin d'être défini comme un champ de classe.

Pourrait obtenir la capacité effective via: capacity()


Opérations

  • Trouver l'entité par clé.
    Recherchez d'abord le compartiment par valeur de hachage, puis bouclez la liste chaînée ou recherchez l'arbre trié.
  • Ajouter une entité avec une clé.
    Trouvez d'abord le compartiment en fonction de la valeur de hachage de la clé.
    Ensuite essayez de trouver la valeur:
    • Si trouvé, remplacez la valeur.
    • Sinon, ajoutez un nouveau nœud au début de la liste chaînée, ou insérer dans l'arbre trié.
  • Redimensionner
    Lorsque threshold atteint, doublera la capacité de hashtable(table.length), puis effectuera un re-hachage sur tous les éléments pour reconstruire la table.
    Cela pourrait être une opération coûteuse.

Performance

  • obtenir et mettre
    La complexité temporelle est O(1), car:
    • Le compartiment est accessible via l'index du tableau, donc O(1).
    • La liste chaînée dans chaque compartiment est de petite longueur, pourrait donc être vue comme O(1).
    • La taille de l'arbre est également limitée, car étendra la capacité et le re-hachage lorsque le nombre d'éléments augmente, donc pourrait le voir comme O(1), pas O(log N).
 21
Author: Eric Wang, 2018-08-29 11:10:24

Le hashcode détermine quel compartiment pour le hashmap à vérifier. S'il y a plus d'un objet dans le compartiment, une recherche linéaire est effectuée pour trouver quel élément dans le compartiment est égal à l'élément souhaité (en utilisant la méthode equals()).

En d'autres termes, si vous avez un hashcode parfait, l'accès à hashmap est constant, vous n'aurez jamais à parcourir un compartiment (techniquement, vous devrez également avoir des buckets MAX_INT, l'implémentation Java peut partager quelques codes de hachage dans le même compartiment pour réduire les besoins en espace). Si vous avez le pire hashcode (renvoie toujours le même numéro), votre accès hashmap devient linéaire car vous devez rechercher dans chaque élément de la carte (ils sont tous dans le même compartiment) pour obtenir ce que vous voulez.

La plupart du temps, un hashcode bien écrit n'est pas parfait mais est suffisamment unique pour vous donner un accès plus ou moins constant.

 14
Author: Pace, 2011-06-27 13:34:13

Vous vous trompez sur le point trois. Deux entrées peuvent avoir le même code de hachage mais ne pas être égales. Jetez un oeil à l'implémentation de HashMap.obtenir de l'OpenJDK. Vous pouvez voir qu'il vérifie que les hachages sont égaux et que les clés sont égales. Si le point trois était vrai, il serait inutile de vérifier que les clés sont égales. Le code de hachage est comparé avant la clé car le premier est une comparaison plus efficace.

Si vous souhaitez en apprendre un peu plus à ce sujet, jetez un œil à l'article Wikipedia sur Open Addressing collision resolution, qui, je crois, est le mécanisme utilisé par l'implémentation OpenJDK. Ce mécanisme est subtilement différent de l'approche "seau" mentionnée par l'une des autres réponses.

 11
Author: Leif Wickland, 2016-01-07 06:52:26

C'est une question des plus déroutantes pour beaucoup d'entre nous dans les Interviews.Mais ce n'est pas si complexe.


Nous savons

  • HashMap magasins paire clé-valeur dans la Carte.Entrée (nous le savons tous)

  • HashMap fonctionne sur l'algorithme de hachage et utilise hashCode() et la méthode equals() dans les méthodes put() et get (). (même nous le savons)

  • When we call put method by passing key-value pair, HashMap uses Key **hashCode()** with hashing to **find out the index** to store the key-value pair. (this is important)

  • The Entry is **stored in the LinkedList**, so if there are already existing entry, it uses **equals() method to check if the passed key already exists** (even this is important)

  • Si oui, il écrase la valeur sinon il crée une nouvelle entrée et stocke cette entrée clé-valeur.

  • Lorsque nous appelons get par un passage à la Clé, encore une fois, il utilise le hashCode() pour trouver l'index, dans le tableau, et ensuite utiliser méthode equals() pour trouver la bonne Entrée et retourner la valeur. (c'est évident)

CETTE IMAGE VOUS AIDERA À COMPRENDRE:

Modifier septembre 2017: ici nous voyons comment la valeur de hachage si elle est utilisée avec des égaux après avoir trouvé seau.

if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

}

entrez la description de l'image ici

 7
Author: VedX, 2017-09-20 08:32:57
import java.util.HashMap;

public class Students  {
    String name;
    int age;

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

    @Override
    public int hashCode() {
        System.out.println("__hash__");
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        System.out.println("__eq__");
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Students other = (Students) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    public static void main(String[] args) {

        Students S1 = new Students("taj",22);
        Students S2 = new Students("taj",21);

        System.out.println(S1.hashCode());
        System.out.println(S2.hashCode());

        HashMap<Students,String > HM = new HashMap<Students,String > (); 
        HM.put(S1, "tajinder");
        HM.put(S2, "tajinder");
        System.out.println(HM.size());
    }
}

Output:

__ hash __

116232

__ hash __

116201

__ hash __

__ hash __

2

Donc ici nous voyons que si les deux objets S1 et S2 ont un contenu différent, alors nous sommes à peu près sûrs que notre méthode Hashcode surchargée générera un Hashcode différent(116232,11601) pour les deux objets. MAINTENANT, puisqu'il existe différents codes de hachage, il ne prendra même pas la peine d'appeler la méthode EQUALS. Parce qu'un Hashcode différent GARANTIT un contenu DIFFÉRENT dans un objet.

    public static void main(String[] args) {

        Students S1 = new Students("taj",21);
        Students S2 = new Students("taj",21);

        System.out.println(S1.hashCode());
        System.out.println(S2.hashCode());

        HashMap<Students,String > HM = new HashMap<Students,String > (); 
        HM.put(S1, "tajinder");
        HM.put(S2, "tajinder");
        System.out.println(HM.size());
    }
}

Now lets change out main method a little bit. Output after this change is 

__ hash __

116201

__ hash __

116201

__ hash __

__ hash __

__ eq __

1
We can clearly see that equal method is called. Here is print statement __eq__, since we have same hashcode, then content of objects MAY or MAY not be similar. So program internally  calls Equal method to verify this. 


Conclusion 
If hashcode is different , equal method will not get called. 
if hashcode is same, equal method will get called.

Thanks , hope it helps. 
 4
Author: Tajinder Singh, 2014-06-01 11:25:33

Hachage carte fonctionne sur le principe du hachage

La méthode HashMap get(Key k) appelle la méthode hashCode sur l'objet key et applique hashValue retournée à sa propre fonction de hachage statique pour trouver un emplacement de compartiment(tableau de sauvegarde) où les clés et les valeurs sont stockées sous la forme d'une classe imbriquée appelée Entry (Map.Entrée) . Vous avez donc conclu que, à partir de la ligne précédente, la clé et la valeur sont stockées dans le compartiment en tant qu'objet d'entrée . Donc en pensant que seule la valeur est stockée dans le seau n'est pas correct et ne donnera pas une bonne impression sur l'intervieweur .

  • Chaque fois que nous appelons la méthode get( Key k ) sur l'objet HashMap . Tout d'abord, il vérifie si la clé est nulle ou non . Notez qu'il ne peut y avoir qu'une seule clé null dans HashMap .

Si key est null , alors les clés Null correspondent toujours à hash 0, donc indexent 0.

Si key n'est pas null , il appellera hashfunction sur l'objet key , voir ligne 4 dans la méthode ci-dessus, c'est-à-dire key.hashCode (), donc après la clé.hashCode() renvoie hashValue, la ligne 4 ressemble à

            int hash = hash(hashValue)

Et maintenant ,il applique hashValue retourné dans sa propre fonction de hachage .

Nous pourrions nous demander pourquoi nous calculons à nouveau la valeur de hachage en utilisant hash(hashValue). La réponse est qu'il défend contre les fonctions de hachage de mauvaise qualité.

Maintenant, final hashvalue est utilisé pour trouver l'emplacement du compartiment dans lequel l'objet Entry est stocké . L'objet Entry stocke dans le compartiment comme ceci (hash,key,value,buckettindex)

 2
Author: user217292, 2014-08-04 09:39:17

Chaque objet d'entrée représente la paire clé-valeur. Le champ suivant fait référence à un autre objet d'entrée si un compartiment a plus d'une entrée.

Parfois, il peut arriver que les hashCodes pour 2 objets différents soient les mêmes. Dans ce cas, 2 objets seront enregistrés dans un compartiment et seront présentés sous forme de LinkedList. Le point d'entrée est un objet ajouté plus récemment. Cet objet fait référence à un autre objet avec le champ suivant et donc un. La dernière entrée fait référence à null. Lorsque vous créez HashMap avec défaut constructeur

Le tableau est créé avec la taille 16 et l'équilibre de charge par défaut 0.75.

entrez la description de l'image ici

(Source)

 2
Author: Premraj, 2015-02-16 12:02:43

Je n'entrerai pas dans les détails du fonctionnement de HashMap, mais je donnerai un exemple afin que nous puissions nous souvenir du fonctionnement de HashMap en le reliant à la réalité.

Nous avons Key, Value ,HashCode et bucket.

Pendant un certain temps, nous allons relier chacun d'eux avec ce qui suit:

  • Seau- > Une société
  • HashCode - > Adresse de la société (unique toujours)
  • Valeur- > Une maison dans la Société
  • Clé -> Adresse de la maison.

Utilisation de la carte.obtenir (clé):

Stevie veut se rendre à la maison de son ami(Josse) qui vit dans une villa dans une société VIP, que ce soit la société JavaLovers. L'adresse de Josse est son SSN (qui est différent pour tout le monde). Il y a un index maintenu dans lequel nous trouvons le nom de la société basé sur SSN. Cet indice peut être considéré comme un algorithme pour trouver le HashCode.

  • Nom de la société SSN
  • 92313(Josse) Jav JavaLovers
  • 13214 Ang AngularJSLovers
  • 98080 -- JavaLovers
  • 53808 Bi BiologyLovers

  1. Ce SSN(clé) nous donne d'abord un HashCode(de la table d'index) qui n'est rien d'autre que le nom de la société.
  2. Maintenant, plusieurs maisons peuvent être dans la même société, donc le HashCode peut être commun.
  3. Supposons que la Société soit commune pour deux maisons, comment allons-nous identifier quelle maison nous allons, oui, en utilisant la clé (SSN) qui n'est rien d'autre que l'adresse de la maison

En utilisant Cartographie.mettre (clé, valeur)

Cela trouve une société appropriée pour cette valeur en trouvant le HashCode, puis la valeur est stockée.

J'espère que cela aide et que cela est ouvert aux modifications.

 1
Author: Prashant K, 2015-05-17 06:49:32

Sous une forme résumée de la façon dont HashMap fonctionne en java?

HashMap fonctionne sur le principe du hachage, nous avons mis() et get() méthode pour stocker et récupérer l'objet de HashMap. Lorsque nous passons à la fois la clé et la valeur à la méthode put() pour stocker sur HashMap, elle utilise la méthode key object hashcode() pour calculer hashcode et en appliquant le hachage sur ce hashcode, elle identifie l'emplacement du compartiment pour stocker l'objet value. Lors de la récupération, il utilise la méthode key object equals pour le savoir corriger la paire clé-valeur et renvoyer l'objet valeur associé à cette clé. HashMap utilise la liste chaînée en cas de collision et l'objet sera stocké dans le nœud suivant de la liste chaînée. HashMap stocke également les deux tuple clé+valeur dans chaque nœud de la liste chaînée.

 1
Author: JAVA, 2017-01-17 03:58:34

Deux objets sont égaux, implique qu'ils ont le même hashcode, mais pas l'inverse

Mise à jour de Java 8 dans HashMap -

Vous effectuez cette opération dans votre code -

myHashmap.put("old","key-value-pair");
myHashMap.put("very-old","old-key-value-pair");

Donc, supposons que votre hashcode retourné pour les deux clés "old" et "very-old" est le même. Alors ce qui va se passer.

myHashMap est un HashMap, et supposons qu'au départ vous n'ayez pas spécifié sa capacité. Donc, la capacité par défaut selon java est de 16. Alors maintenant, dès que vous avez initialisé hashmap en utilisant le nouveau mot-clé, il a créé 16 compartiments. maintenant, lorsque vous avez exécuté la première instruction -

myHashmap.put("old","key-value-pair");

Alors hashcode pour "old" est calculé, et parce que le hashcode pourrait être très grand entier aussi, donc, java a fait cela en interne - (hash est hashcode ici et > > > est le décalage à droite)

hash XOR hash >>> 16

Donc pour donner une image plus grande, il renverra un index, qui serait compris entre 0 et 15. Maintenant, votre paire de valeurs clés "old" et "key-value-pair" serait convertie en instance de clé et de valeur de l'objet Entry variable. et puis cet objet d'entrée sera stocké dans le compartiment, ou vous pouvez dire qu'à un index particulier, cet objet d'entrée sera stocké.

FYI - Entry est une classe dans Map interface - Map.Entrée, avec ces signature / définition

class Entry{
          final Key k;
          value v;
          final int hash;
          Entry next;
}

Maintenant, lorsque vous exécutez l'instruction suivante -

myHashmap.put("very-old","old-key-value-pair");

Et "very-old" donnent le même hashcode que "old", donc cette nouvelle paire de valeurs clés est à nouveau envoyée au même index ou au même compartiment. Mais puisque ce seau n'est pas vide, alors le next la variable de l'objet Entry est utilisée pour stocker cette nouvelle paire clé-valeur.

Et cela sera stocké sous forme de liste chaînée pour chaque objet qui a le même hashcode, mais un TRIEFY_THRESHOLD est spécifié avec la valeur 6. donc, après cette atteinte, la liste chaînée est convertie en arbre équilibré (arbre rouge-noir) avec le premier élément comme racine.

 1
Author: theanubhava, 2017-07-16 17:27:23

, Comme on dit, une image vaut 1000 mots. Je dis: un code vaut mieux que 1000 mots. Voici le code source de HashMap. Méthode Get:

/**
     * Implements Map.get and related methods
     *
     * @param hash hash for key
     * @param key the key
     * @return the node, or null if none
     */
    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

Il devient donc clair que hash est utilisé pour trouver le "bucket" et le premier élément est toujours vérifié dans ce bucket. Sinon, alors equals de la clé est utilisé pour trouver l'élément réel dans la liste chaînée.

Voyons la méthode put():

  /**
     * Implements Map.put and related methods
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to put
     * @param onlyIfAbsent if true, don't change existing value
     * @param evict if false, the table is in creation mode.
     * @return previous value, or null if none
     */
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

C'est un peu plus compliqué, mais il devient clair que le nouvel élément est mettez dans l'onglet à la position calculée en fonction du hachage:

i = (n - 1) & hash ici i est l'index où le nouvel élément sera mis (ou c'est le "compartiment"). n est la taille du tableau tab (tableau de "seaux").

Tout d'abord, on essaie de le mettre comme premier élément de ce "seau". S'il existe déjà un élément, ajoutez un nouveau nœud à la liste.

 0
Author: ACV, 2016-09-22 20:40:21

Ça va être une longue réponse, prenez un verre et lisez la suite {

Le hachage consiste à stocker une paire clé-valeur en mémoire qui peut être lue et écrite plus rapidement. Il stocke les clés dans un tableau et les valeurs dans une liste de liens .

Disons que je veux stocker 4 paires de valeurs clés -

{
“girl” => “ahhan” , 
“misused” => “Manmohan Singh” , 
“horsemints” => “guess what”, 
“no” => “way”
}

, Afin de stocker les clés nous avons besoin d'un tableau de 4 éléments . Maintenant, comment puis-je mapper l'une de ces 4 clés à 4 index de tableau (0,1,2,3)?

Donc java trouve le hashCode des clés individuelles et les mapper à un index de tableau . Les formules de Hashcode sont -

1) reverse the string.

2) keep on multiplying ascii of each character with increasing power of 31 . then add the components .

3) So hashCode() of girl would be –(ascii values of  l,r,i,g are 108, 114, 105 and 103) . 

e.g. girl =  108 * 31^0  + 114 * 31^1  + 105 * 31^2 + 103 * 31^3  = 3173020

Hash et fille !! Je sais ce que vous pensez. Votre fascination pour ce duo sauvage pourrait vous faire manquer une chose importante .

Pourquoi java le multiplie par 31 ?

C'est parce que, 31 est un nombre premier impair sous la forme 2^5 – 1 . Et odd prime réduit le risque de collision de hachage

Maintenant, comment ce code de hachage est mappé à un tableau index?

La réponse est, Hash Code % (Array length -1) . Donc “girl” est mappé à (3173020 % 3) = 1 dans notre cas . qui est le deuxième élément du tableau .

Et la valeur "ahhan" est stockée dans une LinkedList associée à array index 1 .

HashCollision - Si vous essayez de trouver hasHCode des clés “misused” et “horsemints” en utilisant les formules décrites ci-dessus, vous verrez les deux nous donner le même 1069518484. Whooaa !! leçon apprise -

2 objets égaux doivent avoir le même hashCode mais il n'est pas une garantie si le hashCode correspond alors les objets sont égaux . Donc, il devrait en magasin les deux valeurs correspondant à "misused" et "horsemints" au compartiment 1 (1069518484 % 3) .

Maintenant, la carte de hachage ressemble à -

Array Index 0 –
Array Index 1 - LinkedIst (“ahhan” , “Manmohan Singh” , “guess what”)
Array Index 2 – LinkedList (“way”)
Array Index 3 – 

Maintenant , si un corps essaie de trouver la valeur de la clé “horsemints”, java trouvera rapidement le hashCode de celle-ci, le module et commencera à rechercher sa valeur dans la LinkedList correspondante index 1 . Donc, de cette façon, nous n'avons pas besoin de rechercher tous les 4 index de tableau rendant ainsi l'accès aux données plus rapide.

Mais, attendez, une seconde . il y a 3 valeurs dans cet index de tableau correspondant linkedList 1, comment il découvre lequel était la valeur de la clé "horsemints"?

En fait, j'ai menti, quand j'ai dit que HashMap ne stockait que des valeurs dans LinkedList .

Il stocke les deux paires de valeurs clés en tant qu'entrée de carte. Donc, en fait, la Carte ressemble à ceci .

Array Index 0 –
Array Index 1 - LinkedIst (<”girl” => “ahhan”> , <” misused” => “Manmohan Singh”> , <”horsemints” => “guess what”>)
Array Index 2 – LinkedList (<”no” => “way”>)
Array Index 3 – 

Maintenant, vous pouvez voir En parcourant la linkedList correspondante pour ArrayIndex1, il compare en fait la clé de chaque entrée à celle de LinkedList à "horsemints" et lorsqu'il en trouve une, il en renvoie simplement la valeur .

J'espère que vous vous êtes amusé en le lisant:)

 -1
Author: sapy, 2016-03-20 11:12:26