Comme il existe une certaine confusion sur l'algorithme utilisé par HashMap de Java (dans l'implémentation Sun / Oracle / OpenJDK), voici les extraits de code source pertinents (à partir d'OpenJDK, 1.6.0_20, sur Ubuntu):
/**
* Returns the entry associated with the specified key in the
* HashMap. Returns null if the HashMap contains no mapping
* for the key.
*/
final Entry<K,V> getEntry(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
Cette méthode (cite est des lignes 355 à 371) est appelée lors de la recherche d'une entrée dans le tableau, par exemple from get()
, containsKey()
et quelques autres. La boucle for parcourt ici la liste chaînée formée par les objets d'entrée.
Voici le code des objets d'entrée (lignes 691-705 + 759):
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
final int hash;
/**
* Creates new entry.
*/
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
// (methods left away, they are straight-forward implementations of Map.Entry)
}
Juste après cela vient la addEntry()
méthode:
/**
* Adds a new entry with the specified key, value and hash code to
* the specified bucket. It is the responsibility of this
* method to resize the table if appropriate.
*
* Subclass overrides this to alter the behavior of put method.
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
Cela ajoute la nouvelle entrée sur le devant du compartiment, avec un lien vers l'ancienne première entrée (ou null, s'il n'y en a pas). De même, la removeEntryForKey()
méthode parcourt la liste et se charge de ne supprimer qu'une seule entrée, laissant le reste de la liste intact.
Donc, voici une liste d'entrées liées pour chaque bucket, et je doute fort que cela ait changé de _20
à _22
, car c'était comme ça à partir de la 1.2.
(Ce code est (c) 1997-2007 Sun Microsystems, et disponible sous GPL, mais pour copier mieux utiliser le fichier original, contenu dans src.zip dans chaque JDK de Sun / Oracle, et aussi dans OpenJDK.)