La mayoría de ustedes estarán de acuerdo en que
Puede leer más sobre esto aquí: Trabajar con hashCode y el método igual en Java
HashMap
, hoy en día, es el tema favorito de discusión durante las entrevistas. A veces tuve discusiones similares con mis colegas y realmente me ayudó. Ahora tendré esa discusión contigo. Supongo que si está interesado en los aspectos internos y el funcionamiento de HashMap, entonces ya está familiarizado con los conceptos básicos de HashMap , así que me saltaré esa parte. Pero si eres nuevo en esto, te sugiero que visites el sitio Java Docs . Antes de continuar, le recomiendo que consulte mi artículo anterior: Trabajar con hashCode y el método igual en Java. Contenido de este artículo:
- La única respuesta posible.
- ¿Qué es el hash?
- Un poco sobre la clase
Entry
. - Lo que hace el
put()
. - Cómo funciona el método
get()
. - Notas
La única respuesta posible
Si alguien me pide que le explique "¿ Cómo funciona HashMap?" ", simplemente responderé: " Según los principios de Hashing ". No podría ser más sencillo. Para comprender esto y obtener una respuesta ampliada, debe asegurarse de conocer los conceptos básicos de Hashing. ¿Bien?¿Qué es el hash?
El hash en su forma más simple es una forma de convertir cualquier variable/objeto en un código único después de aplicar cualquier fórmula/algoritmo a sus propiedades. Una función hash verdadera debe seguir la siguiente regla: una función hash debe devolver el mismo código hash siempre que se aplique a objetos iguales o iguales. En otras palabras, dos objetos idénticos deben devolver a su vez los mismos códigos hash.Nota: Todos los objetos en Java heredan la implementación estándar hashCode() de la función descrita en la clase Object . Esta función devuelve un código hash obtenido al convertir la dirección interna de un objeto en un número, lo que conduce a la creación de un código único para cada objeto individual. |
Un poco sobre la clase de Entrada.
Por definición, un mapa es “un objeto que almacena valores y claves en pares”. Bastante simple, ¿verdad? Entonces, ¿debe haber algún tipo de mecanismo en HashMap que almacene pares de Valores y Claves? Respuesta: sí.HashMap
tiene una clase interna Entry
que se ve así:
static class Entry implements Map.Entry
{
final K key;
V value;
Entry next;
final int hash;
...//остальной código тут…
}
Naturalmente, la clase Entry
tiene una clave y un valor almacenados como atributos. La clave está marcada como final
y también vemos dos campos adicionales: next
y hash
. Intentaremos comprender el propósito de estos campos a medida que avance el artículo.
¿Qué hace el método Java put()?
Antes de profundizar en la implementación del métodoput()
, es muy importante comprender que las instancias de una clase Entry
se almacenan en una matriz. La clase HashMap define esta variable como:
/**
* Размер таблицы, изменяется при необходимости. Длина всегда должна быть
* кратна двум!
*/
transient Entry[] table;
Ahora eche un vistazo al código de implementación del método put()
:
/**
* Связывает определенное significado с определенным ключом в этой карте(map).
* Если карта перед этим содержала significado для данного ключа, это significado
* заменится на новое.
*
* @param key
* ключ с которым указанное significado должно быть связано.
* @param value
* significado которое должно быть связано с ключом.
* @return вернет предыдущее significado связанное с key, o null
* если не было значений связанных с key. (Вернет null
* так же, если перед этим key был связан со significadoм null)
*/
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<k , V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
Averigüémoslo paso a paso:
- En primer lugar, comprobamos si la clave existe. Si la clave no existe ( ), el valor se coloca en la tabla en la posición
null
cero porque el código hash para el valor esnull
,.это – всегда 0
- En el siguiente paso, el valor hash se calcula utilizando el código hash de la clave obtenida llamando al método
hashCode()
. Este valor hash se utiliza para calcular la posición en la matriz donde se colocará el objetoEntry
. Los diseñadores del JDK asumieron que una función mal escritahashCode()
podría devolver un valor hash demasiado alto o demasiado bajo. Para resolver este problema, introdujeron otrahash()
función y le pasaron el valor hash de un objeto para que el valor hash coincidiera con el tamaño de la matriz. - Ahora se llama a la función
indexFor(hash, table.length)
para calcular la posición exacta donde se colocará el objetoEntry
. - Aquí comienza la parte principal.
LinkedList
Ahora, basándonos en lo que sabemos de que dos objetos desiguales pueden tener códigos hash iguales , hacemos la pregunta: ¿Se colocarán dos objetos diferentes en la misma posición en la matriz [bucket]? Si recuerdas, la claseEntry
tiene un atributo "next
". Este atributo siempre apunta al siguiente objeto de la cadena. Este es exactamente el comportamientoLinkedList
.
Entry
se almacenan en el formulario LinkedList
. Cuando se va a colocar un objeto Entry
en una ubicación específica, HashMap verifica si ya existe una entrada en esa ubicación. Si no hay entrada, entonces el objeto se coloca en esta posición. Sin embargo, si ya hay un objeto en esta posición, se comprueba el siguiente atributo. Si regresa null
y el objeto actual Entry
se convierte en el siguiente enlace del archivo LinkedList
. Si la siguiente variable no lo es null
, se repite el procedimiento para la siguiente hasta encontrarla null
. ¿Qué pasa si ponemos otro objeto con un valor diferente pero con la misma clave que antes? Lógicamente, esto debería dar como resultado que se reemplace el valor anterior. ¿Como sucedió esto? En general, después de determinar la posición de un objeto Entry
, mientras atraviesa LinkedList
hasta la posición calculada, HashMap
llama al método de comparación de claves para cada objeto Entry
. Todos estos Entry
objetos LinkedList
pueden tener códigos hash similares, pero el método equals()
comprobará la verdadera similitud. Esto solo reemplazará el valor dentro del archivo Entry
. Por tanto, HashMap garantiza la unicidad de todas las claves.
¿Cómo funciona el método get() de Java?
Ahora tenemos una idea de cómo se almacenan los pares clave-valorHashMap
. La siguiente gran pregunta es: ¿Qué sucede cuando un objeto pasa de un HashMap a un método get()
? ¿Cómo se determina el valor de un objeto? Ya deberíamos saber la respuesta, porque la forma en que se determina la unicidad de una clave en el método put()
tiene la misma lógica que aplica el método get()
. Una vez que HashMap
determina la clave del objeto pasado como argumento, simplemente devuelve el valor del correspondiente Entry
. Si no se encuentran coincidencias, el método get()
devolverá null
. Echemos un vistazo al código:
public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = 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.equals(k)))
return e.value;
}
return null;
}
El código anterior es similar al método put()
hasta este punto if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
, después de eso simplemente devuelve el valor del objeto.
Notas
- La estructura de datos que se almacenará en un objeto
Entry
es una matriz con un nombretable
y un tipoEntry
. - Cada posición individual en la matriz se llama depósito porque puede contener el primer elemento
LinkedList
de los objetosEntry
. hashCode()
La clave es necesaria para calcular la posición del objetoEntry
.equals()
La clave se utiliza para verificar la unicidad de la clave en el mapa (map
).hashCode()
yequals()
los valores no se utilizan en métodosget()
niset()
enHashMap
.- El código hash para claves con un valor
null
es siempre 0. Y dicho objetoEntry
siempre se almacenará en la posición cero de la matriz.
GO TO FULL VERSION