Comment un Java HashMap de gérer les différents objets avec le même code de hachage?
Selon ma compréhension que j'en pense:
- Il est parfaitement légal pour les deux objets ont le même hashcode.
- Si deux objets sont égaux (à l'aide de la méthode equals ()), alors qu'ils ont le même hashcode.
- Si deux objets ne sont pas égaux, ils ne peuvent pas avoir le même hashcode
Suis-je la corriger?
Maintenant, si ne me trompe pas, j'ai la question suivante:
Le HashMap
utilise en interne le hashcode de l'objet. Donc, si deux objets ont la même hashcode, alors comment peut - HashMap
suivre les clés qu'elle utilise?
Quelqu'un peut m'expliquer comment le HashMap
utilise en interne le hashcode de l'objet?
- Pour l'enregistrement: #1 et #2 sont correctes, #3 est faux: Deux objets qui ne sont pas égaux peuvent avoir le même code de hachage.
- #1 et #3 sont contradictoires même
- En effet, si #2 n'est pas respectée, alors la equals() de la mise en œuvre (ou sans doute le hashCode()) est incorrect.
Vous devez vous connecter pour publier un commentaire.
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'elle utilise pour stocker des paires clé-valeur dans. Chaque compartiment dispose d'un numéro unique - c'est ce qui identifie le seau. Quand vous mettez une paire clé-valeur dans la carte, la table de hachage va regarder le code de hachage de la clé, et de stocker la paire dans le seau dont l'identificateur est le code de hachage de la clé. Par exemple: Le code de hachage de la clé est de 235 -> la paire est stocké dans un seau numéro 235. (À noter qu'un compartiment peut stocker plus d'une paire clé-valeur).
Lorsque vous recherche une valeur dans la table de hachage, en lui donnant une touche, il va d'abord regarder le code de hachage de la clé que vous avez donné. La table de hachage va ensuite chercher dans le seau, puis il compare la clé qui vous a donné les clés de toutes les paires dans le seau, en les comparant avec
equals()
.Maintenant, vous pouvez voir comment cela est très efficace pour la recherche de paires clé-valeur dans une carte: par le code de hachage de la clé de la table de hachage sait immédiatement où seau à regarder, de sorte qu'il n'a qu'à tester par rapport à ce qui est dans le seau.
Regardant le mécanisme ci-dessus, vous pouvez également voir quelles sont les conditions nécessaires sur la
hashCode()
etequals()
méthodes de touches:Si les deux touches sont les mêmes (
equals()
retournetrue
lorsque vous comparez entre eux), leurhashCode()
méthode doit renvoyer le même nombre. Si les touches de violer la présente, ensuite, les clés de l'égalité peuvent être stockées dans des compartiments différents, et la table de hachage ne serait pas en mesure de trouver des paires clé-valeur (parce qu'il va dans le même seau).Si les deux clés sont différentes, alors il n'a pas d'importance si leurs codes de hachage sont les mêmes ou pas. Ils seront stockés dans le même seau si leurs codes de hachage sont les mêmes, et dans ce cas, la table de hachage va utiliser
equals()
de les distinguer.hashCode()
méthode retourne différents codes de hachage, puis leequals()
ethashCode()
méthodes de la classe de clé de violer le contrat et vous obtiendrez des résultats étranges lors de l'utilisation de ces clés dans unHashMap
.HashMap
, que vous pouvez trouver dans le fichiersrc.zip
dans votre répertoire d'installation du JDK.HashMap
fonctionne encore si toutes les touches a le même hashcode, mais il serait très inefficace, car tout se passe dans un seau. Trouver quelque chose dans la carte serait alors tout aussi inefficace que de la trouver dans une liste (O(n)).indexFor
où il travaille sur le seau à utiliser.Votre troisième affirmation est incorrecte.
Il est parfaitement légal pour les deux inégale objets ont le même code de hachage. Il est utilisé par
HashMap
comme un "premier filtre passe" pour que la carte peut trouver rapidement possible entrées avec la clé spécifiée. Les touches avec le même code de hachage sont ensuite testés pour l'égalité avec la clé spécifiée.Vous ne voulez pas d'une exigence selon laquelle l'inégalité des objets ne pouvais pas avoir le même code de hachage, car sinon ça serait limite de 232 les objets possibles. (Cela voudrait dire aussi que les différents types ne pouvais même pas utiliser un objet de domaines, afin de générer des codes de hachage, comme les autres classes, pourrait générer de la même table de hachage).
HashMap
est un tableau deEntry
objets.Envisager
HashMap
comme un tableau d'objets.Ont un oeil à ce que ce
Object
est:Chaque
Entry
objet représente une paire clé-valeur. Le domainenext
se réfère à un autreEntry
objet si un seau a plus d'unEntry
.Parfois, il peut arriver que des codes de hachage pour 2 objets différents sont les mêmes. Dans ce cas, deux objets seront enregistrées dans un seau et va être présenté comme une liste chaînée.
Le point d'entrée est le plus récemment ajouté objet. Cet objet fait référence à un autre objet avec la
next
de champ, et ainsi de suite. La dernière entrée se réfère ànull
.Lorsque vous créez un
HashMap
avec le constructeur par défautLe tableau est créé avec la taille 16 et défaut de 0,75 équilibrer la charge.
L'ajout d'une nouvelle paire clé-valeur
hash % (arrayLength-1)
où l'élément doit être placé (seau nombre)HashMap
, alors la valeur est écrasée.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
next
champ fait référence à l'ancien élément.Suppression
hash % (arrayLength-1)
Entry
.Si un élément souhaité n'est pas trouvé, le retour
null
hash % (arrayLength-1)
il seraithash % arrayLength
. Mais il en fait esthash & (arrayLength-1)
. Que est, car il utilise des puissances de deux (2^n
) pour la longueur du tableau, en prenantn
bits de poids faible.int
qui bien sûr peut être négatif, ce faisant, modulo un nombre négatif va vous donner un nombre négatifVous 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(clé, valeur): HashMap magasins à la fois la clé et la valeur de l'objet en tant que Carte.De l'entrée. Hashmap s'applique hashcode () pour obtenir le seau. si il y a collision ,HashMap utilise LinkedList pour stocker des objets.
get(clé): HashMap principales utilisations de l'Objet hashcode pour en savoir seau, puis des touches d'appel.méthode equals() pour identifier le nœud correct dans LinkedList et de retourner la valeur de l'objet de cette clé dans Java HashMap.
Voici une description sommaire de
HashMap
s'mécanisme, pourJava 8
version, (il peut être légèrement différent de la version 6 de Java).Structures de données
La valeur de hachage est calculée à l'aide d'
hash()
sur la clé, et à décider lequel seau de la table de hachage à utiliser pour une clé donnée.Lorsque le nombre d'éléments dans un seau est petit, une seule liste liée est utilisé.
Lorsque le nombre d'éléments dans un seau est grand, rouge-noir arbre est utilisé.
Classes (interne)
Map.Entry
Représenter une entité unique dans la carte, la clé/valeur de l'entité.
HashMap.Node
Liste liée version de nœud.
Il pourrait s'agir d':
Parce qu'il a une valeur de hachage de la propriété.
HashMap.TreeNode
L'arbre de la version de nœud.
Champs (interne)
Node[] table
Le seau de table, (chef de listes chaînées).
Si un seau ne contient pas d'éléments, il est alors nulle, donc que prendre de l'espace de référence.
Set<Map.Entry> entrySet
Ensemble d'entités.
int size
Nombre d'entités.
float loadFactor
Indiquer le degré de remplissage de la table de hachage est autorisé, avant de la redimensionner.
int threshold
La prochaine taille à laquelle redimensionner.
Formule:
threshold = capacity * loadFactor
Méthodes (interne)
int hash(key)
Calculer le hachage à clé.
Comment carte de hachage dans le seau?
Utiliser la logique suivante:
Sur la capacité
Dans la table de hachage, de la capacité signifie que le comte de seau, il pourrait être obtenir de
table.length
.Pourrait également être calculée à l'aide d'
threshold
etloadFactor
, donc pas besoin d'être défini comme un champ de classe.Pourrait obtenir de la capacité effective via:
capacity()
Opérations
D'abord trouver le seau par la valeur de hachage, puis la boucle est lié de recherche ou la liste triée de l'arbre.
D'abord trouver le seau en fonction de la valeur de hachage de la clé.
Ensuite, essayez de trouver la valeur:
Lorsque
threshold
atteint, permettra de doubler la table de hachage de la capacité(table.length
), puis d'effectuer une re-hachage sur tous les éléments de reconstruire la table.Cela pourrait être une opération coûteuse.
Performance
Complexité temporelle est
O(1)
, parce que:O(1)
.O(1)
.O(1)
, pasO(log N)
.Le hashcode détermine le seau pour la table de hachage pour vérifier. Si il n'y a plus d'un objet dans le seau, puis une recherche linéaire est faite pour trouver quel élément dans le seau est égal à l'élément de votre choix (à l'aide de la
equals()
) méthode.En d'autres termes, si vous avez une parfaite hashcode puis hashmap accès est constante, vous n'aurez jamais à itérer dans un seau (techniquement, vous devriez également avoir MAX_INT seaux, l'implémentation de Java peut partager quelques-uns des codes de hachage dans le même seau à réduire les besoins en espace). Si vous avez le pire hashcode (renvoie toujours le même numéro), puis votre hashmap l'accès devient linéaire dans la mesure où vous avez à la recherche par le biais de chaque élément de la carte (ils sont tous dans le même seau) pour obtenir ce que vous voulez.
La plupart du temps bien écrit hashcode n'est pas parfait, mais qui est assez unique pour vous donner plus ou moins constant d'accès.
Vous êtes trompé sur le point trois. Deux entrées peuvent avoir le même code de hachage, mais de ne pas être égal. Jetez un oeil à la mise en œuvre de HashMap.obtenez de l'OpenJdk. Vous pouvez voir qu'il vérifie que les valeurs de hachage sont égaux et que les touches sont égaux. Étaient point trois vrai, alors il serait inutile de vérifier que les clés sont égaux. Le code de hachage est comparé à l'avant de la clé parce que l'ancien est plus efficace en comparaison.
Si vous êtes intéressés à en apprendre un peu plus à propos de cela, jetez un oeil à l'article de Wikipedia sur En Abordant résolution de collision, je crois que c'est le mécanisme de l'OpenJdk mise en œuvre utilise. Ce mécanisme est subtilement différent du "seau" approche de l'une des autres réponses mentionne.
Nous voyons donc ici que si les deux objets S1 et S2 ont des contenus différents, alors nous sommes assez sûrs que notre remplacé la méthode Hashcode va générer différents Hashcode(116232,11601) pour les deux objets. MAINTENANT, étant donné qu'il existe différents codes de hachage, donc il ne sera même pas la peine d'appeler méthode EQUALS. Parce qu'un autre Hashcode GARANTIT un contenu DIFFÉRENT dans un objet.
Chaque Entrée de l'objet représente paire clé-valeur. Champ suivant se réfère à d'autres de l'Entrée de l'objet si un seau a plus d ' 1 Entrée.
Parfois, il peut arriver que hashCodes pour 2 objets différents sont les mêmes. Dans ce cas, les 2 objets sont enregistrés dans un seau et va être présenté comme LinkedList. Le point d'entrée est plus récemment ajoutés objet. Cet objet fait référence à un autre objet avec le champ suivant et ainsi de on. La dernière entrée se réfère à la valeur null.
Lorsque vous créez HashMap avec le constructeur par défaut
Tableau est est créé avec la taille 16 et défaut de 0,75 équilibrer la charge.
(Source)
De hachage carte fonctionne sur le principe du hachage
HashMap get(Clé k) les appels de méthode hashCode de la méthode sur l'objet clé et s'applique retourné hashValue à ses propres statique de la fonction de hachage pour trouver un seau emplacement(sauvegarde array) où les clés et les valeurs sont stockées sous la forme d'une classe imbriquée Entrée (la Carte.D'entrée) . Vous avez donc conclu qu'à partir de la ligne précédente qui à la Fois la clé et la valeur est stockée dans le seau comme un formulaire de Saisie de l'objet . De penser que Seule valeur est stockée dans le seau n'est pas correct et ne donnera pas une bonne impression sur l'intervieweur .
Si la clé est null , Null touches toujours la carte de hachage 0, donc l'index 0.
Si la clé n'est pas null , il va appeler hashfunction sur l'objet de clé , consultez la ligne 4 dans la méthode ci-dessus, c'est à dire la clé.hashCode() ,donc après la clé.hashCode() renvoie hashValue , ligne 4 ressemble à
et maintenant ,il s'applique retourné hashValue dans sa propre fonction de hachage .
Nous pouvons nous demander pourquoi nous sommes le calcul de la hashvalue à nouveau à l'aide de hachage(hashValue). La réponse est qu'Il défend contre la mauvaise qualité des fonctions de hachage.
Maintenant final hashvalue est utilisé pour trouver le seau emplacement de l'Entrée de l'objet est stocké . D'entrée de magasins d'objets dans le seau comme ceci (hachage,clé,valeur,bucketindex)
Je ne vais pas entrer dans les détails de comment HashMap fonctionne, mais donne un exemple afin que nous puissions rappeler comment HashMap œuvres par rapport à la réalité.
Nous avons Clé, Valeur ,HashCode et d'un seau.
Pendant un certain temps, nous vous concernent chacun d'entre eux avec les éléments suivants:
À L'Aide De La Carte.get(clé) :
Stevie veut obtenir de son ami(Josse) de la maison qui vit dans une villa située dans un VIP de la société, que ce soit JavaLovers de la Société.
Josse adresse de son SSN(ce qui est différent pour tout le monde).
Il y a un index maintenu dans lequel on trouve le nom de la Société basée sur le SSN.
Cet indice peut être considéré comme un algorithme pour trouver le HashCode.
À L'Aide De La Carte.put(clé,Valeur)
Ce trouve convenable de la société pour cette Valeur par trouver le HashCode et la valeur est stockée.
J'espère que cette aide, et c'est ouvert aux modifications.
Java 8 update dans la table de hachage-
vous faire cette opération dans votre code -
donc, supposons que votre hashcode renvoyées pour les deux touches
"old"
et"very-old"
est le même. Alors ce qui va se passer.myHashMap
est une table de hachage, et supposons qu'au départ, vous n'avez pas spécifié de ses capacités. Donc par défaut de la capacité par java est de 16 ans. Alors maintenant, dès que vous initialisées à la table de hachage en utilisant le nouveau mot-clé, il a créé 16 seaux. maintenant, quand vous avez exécuté la première déclaration-puis hashcode
"old"
est calculé, et parce que le hashcode pourrait être très grand nombre entier aussi, donc, java interne ne présente - (hachage est hashcode ici et >>> est la touche maj droite)afin de donner une plus grande pictureit va revenir à l'index, ce qui serait entre 0 à 15. Maintenant, votre valeur de la clé de paire
"old"
et"key-value-pair"
serait converti à l'Entrée de l'objet de la clé et de la valeur de la variable d'instance. et puis cette entrée objet est stocké dans le seau, ou vous pouvez dire qu'à un indice particulier, cette entrée de l'objet serait stocké.FYI - l'Entrée est d'une classe dans l'interface de Carte - Carte.L'entrée, avec ces signature/définition
maintenant, lorsque vous exécutez l'instruction suivante -
et
"very-old"
donne le même hashcode comme"old"
, de sorte que cette nouvelle valeur de la clé de la paire est de nouveau envoyé à la même indice ou le même seau. Mais depuis ce compartiment n'est pas vide, alors lanext
variable de l'Entrée de l'objet est utilisée pour stocker cette nouvelle valeur de la clé de la paire.et ce seront stockées sous forme de liste, pour chaque objet qui ont le même hashcode, mais un TRIEFY_THRESHOLD est spécifié avec la valeur 6. donc, après cette atteint, liste chaînée est converti à l'équilibre de l'arbre(rouge-noir tree) avec le premier élément à la racine.
Comme il est dit, une image vaut 1000 mots. Je dis: un peu de code est mieux que 1000 mots. Voici le code source de la table de hachage. La méthode Get:
Ainsi, il devient clair que le hachage est utilisé pour trouver le "seau" et le premier élément est toujours vérifié dans ce seau. Si non, alors
equals
de la clé est utilisée pour trouver le véritable élément de la liste chaînée.Voyons le
put()
méthode:C'est un peu plus compliqué, mais il devient évident que le nouvel élément est mis dans l'onglet à la position calculée en fonction de hachage:
i = (n - 1) & hash
icii
est l'index où le nouvel élément sera mis (ou c'est le "compartiment").n
est la taille de latab
array (array de "compartiments").Tout d'abord, il est tenté d'être mis comme premier élément dans le "seau". Si il y a déjà un élément, puis ajouter un nouveau nœud à la liste.
Il va être une longue réponse , prendre un verre et à lire ...
De hachage est tout au sujet de stocker une paire clé-valeur dans une mémoire qui peut être lu et écrit plus rapidement. Il stocke les clés dans un tableau et les valeurs dans une LinkedList .
Permet de Dire que je veux stocker 4 paires clé-valeur -
Afin de stocker les clés nous avons besoin d'un tableau de 4 éléments . Maintenant, comment puis-je carte un de ces 4 touches à 4 les indices de tableau (0,1,2,3)?
Donc java trouve le hashCode de clés individuelles et les mapper à un index de tableau .
Hashcode Formules est -
De hachage et une fille !! Je sais ce que vous pensez. Votre fascination sur que le duo pourrait fait manquer une chose importante .
Pourquoi java multiplier avec 31 ?
Maintenant comment ce code de hachage est mappé à un tableau d'index?
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 de la matrice .et la valeur “ahhan” est stocké dans une LinkedList associés avec l'index de tableau 1 .
HashCollision - Si vous essayez de trouver
hasHCode
des touches“misused”
et“horsemints”
en utilisant les formules décrites ci-dessus, vous verrez à la fois de nous donner la même1069518484
. Whooaa !! leçon apprise -Maintenant la valeur de hachage de la carte ressemble –
Maintenant si certains corps essaie de trouver la valeur de la clé
“horsemints”
, java va rapidement trouver le hashCode de lui , de module et de commencer la recherche de la valeur dans la LinkedList correspondantindex 1
. Ainsi, de cette façon nous n'avons pas besoin de recherche tous les 4 indices de tableau et donc de faire de l'accès aux données plus rapide.Mais , l'attente , l'un sec . il y a 3 valeurs que linkedList correspondant index de Tableau 1, comment il trouve celui qui a était la valeur de la clé “horsemints” ?
En fait j'ai menti quand j'ai dit que HashMap juste stocke les valeurs dans LinkedList .
Il stocke la valeur de clé de paire comme carte d'entrée. Donc, en fait, la Carte ressemble à ceci .
Maintenant, vous pouvez voir lors du transit à travers la linkedList correspondant à ArrayIndex1 il compare en fait la clé de chaque entrée de la LinkedList pour “horsemints” et quand il en trouve un il retourne la valeur de l'informatique .
Espère que vous avez eu du plaisir lors de la lecture il 🙂