Poiché vi è una certa confusione su quale algoritmo HashMap di Java sta utilizzando (nell'implementazione Sun / Oracle / OpenJDK), qui i frammenti di codice sorgente rilevanti (da OpenJDK, 1.6.0_20, su 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;
}
Questo metodo (la citazione è dalle righe 355 alla 371) viene chiamato quando si cerca una voce nella tabella, ad esempio da get()
, containsKey()
e alcuni altri. Il ciclo for qui passa attraverso l'elenco collegato formato dagli oggetti di ingresso.
Di seguito il codice per gli oggetti di ingresso (righe 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)
}
Subito dopo arriva il addEntry()
metodo:
/**
* 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);
}
Questo aggiunge la nuova voce sulla parte anteriore del bucket, con un collegamento alla vecchia prima voce (o null, se non esiste). Allo stesso modo, il removeEntryForKey()
metodo passa attraverso l'elenco e si occupa di eliminare solo una voce, lasciando intatto il resto dell'elenco.
Quindi, ecco un elenco di voci collegate per ogni bucket, e dubito molto che sia cambiato da _20
a _22
, poiché era così da 1.2 in poi.
(Questo codice è (c) 1997-2007 Sun Microsystems, e disponibile sotto GPL, ma per copiare meglio usare il file originale, contenuto in src.zip in ogni JDK da Sun / Oracle, e anche in OpenJDK.)