Como hay cierta confusión acerca de lo que HashMap del algoritmo de Java es el uso (en el/implementación de Sun de Oracle/OpenJDK), aquí los fragmentos de código fuente pertinente (de OpenJDK, 1.6.0_20, en 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;
}
Este método (cita desde las líneas 355 a 371) se invoca al buscar una entrada en la tabla, por ejemplo, desde get()
, containsKey()
y algunos otros. El bucle for aquí va a través de la lista enlazada formada por los objetos de entrada.
el código aquí los objetos de entrada (líneas 691 a 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)
}
Justo después de esto viene la addEntry()
método:
/**
* 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);
}
Esto añade la nueva entrada en la parte frontal del segmento, con un enlace a la antigua primera entrada (o nulo, si no hay tal). De manera similar, el método removeEntryForKey()
pasa por la lista y se encarga de eliminar solo una entrada, dejando intacto el resto de la lista.
Por lo tanto, aquí hay una lista de entradas vinculadas para cada segmento, y dudo mucho de que esto haya cambiado de _20
a _22
, ya que era así desde 1.2 en adelante.
(Este código es (c) 1997-2007 Sun Microsystems, y está disponible bajo GPL, pero para copiar mejor use el archivo original, contenido en src.zip en cada JDK de Sun/Oracle, y también en OpenJDK.)
En el caso de la primera opción , ¿hay alguna razón por la que se utiliza una lista vinculada en lugar de una matriz o incluso un árbol de búsqueda binario? –
la explicación anterior es de alto nivel, no creo que haga mucha diferencia en cuanto a la lista vinculada frente a la matriz.Creo que un árbol de búsqueda binario sería excesivo. También creo que si profundizas en cosas como ConcurrentHashMap y otros, hay muchos detalles de implementación de bajo nivel que pueden hacer una diferencia en el rendimiento, que la explicación de alto nivel anterior no explica. – ams
Si se utiliza el encadenamiento, cuando se le da una clave, ¿cómo sabemos qué artículo recuperar? – ChaoSXDemon