¿Cómo maneja un Java HashMap diferentes objetos con el mismo código hash?


Según mi entendimiento pienso:

  1. Es perfectamente legal que dos objetos tengan el mismo hashcode.
  2. Si dos objetos son iguales (usando el método equals ()) entonces tienen el mismo hashcode.
  3. Si dos objetos no son iguales, entonces no pueden tener el mismo hashcode

¿Estoy en lo cierto?

Ahora bien, si estoy en lo correcto, tengo la siguiente pregunta: El HashMap utiliza internamente el hashcode del objeto. Así que si dos objetos pueden tener el mismo hashcode, entonces ¿cómo puede el HashMap rastrear qué clave utiliza?

¿Puede alguien explicar cómo el HashMap utiliza internamente el hashcode del objeto?

Author: Chris Gong, 2011-06-27

16 answers

Un hashmap funciona así (esto es un poco simplificado, pero ilustra el mecanismo básico):

Tiene una serie de "cubos" que utiliza para almacenar pares clave-valor. Cada cubo tiene un número único - que es lo que identifica el cubo. Cuando coloca un par clave-valor en el mapa, el hashmap mirará el código hash de la clave y almacenará el par en el cubo cuyo identificador es el código hash de la clave. Por ejemplo: El código hash de la clave es 235 - > el par se almacena en el cubo número 235. (Tenga en cuenta que un cubo puede almacenar más de un par clave-valor).

Cuando busca un valor en el hashmap, dándole una clave, primero verá el código hash de la clave que dio. El hashmap entonces buscará en el cubo correspondiente, y luego comparará la clave que dio con las claves de todos los pares en el cubo, comparándolas con equals().

Ahora puede ver cómo esto es muy eficiente para buscar pares clave-valor en un mapa: por el código hash de la clave, el hashmap sabe inmediatamente en qué cubo buscar, por lo que solo tiene que probar con lo que hay en ese cubo.

Mirando el mecanismo anterior, también puede ver qué requisitos son necesarios en los métodos de claves hashCode() y equals():

  • Si dos claves son iguales (equals() devuelve true cuando las compara), su método hashCode() debe devolver el mismo número. Si las claves violan esto, entonces las claves que son iguales pueden almacenarse en diferentes cubos, y el hashmap no sería capaz de encontrar pares clave-valor (porque va a buscar en el mismo cubo).

  • Si dos claves son diferentes, entonces no importa si sus códigos hash son los mismos o no. Se almacenarán en el mismo cubo si sus códigos hash son los mismos, y en este caso, el hashmap usará equals() para distinguirlos.

 297
Author: Jesper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-05 00:16:30

Su tercera afirmación es incorrecta.

Es perfectamente legal que dos objetos desiguales tengan el mismo código hash. Es utilizado por HashMap como un "filtro de primer paso" para que el mapa pueda encontrar rápidamente posibles entradas con la clave especificada. Las claves con el mismo código hash se prueban para la igualdad con la clave especificada.

Usted no querría un requisito de que dos objetos desiguales no puedan tener el mismo código hash, ya que de lo contrario eso lo limitaría a 232 posibles objetos. (También significaría que diferentes tipos ni siquiera podrían usar los campos de un objeto para generar códigos hash, ya que otras clases podrían generar el mismo hash.)

 80
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-23 13:29:11

Diagrama de estructura de HashMap

HashMap es una matriz de objetos Entry.

Considere HashMap como solo una matriz de objetos.

Echa un vistazo a lo que esto Object es:

static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        final int hash;
… 
}

Cada objeto Entry representa un par clave-valor. El campo next se refiere a otro objeto Entry si un cubo tiene más de un Entry.

A veces puede suceder que los códigos hash para 2 objetos diferentes sean los mismos. En este caso, dos objetos se guardarán en un cubo y se presentarán como un lista enlazada. El punto de entrada es el objeto añadido más recientemente. Este objeto se refiere a otro objeto con el campo next y así sucesivamente. La última entrada se refiere a null.

Cuando se crea un HashMap con el constructor predeterminado

HashMap hashMap = new HashMap();

La matriz se crea con un tamaño 16 y un equilibrio de carga predeterminado de 0.75.

Añadiendo un nuevo par clave-valor

  1. Calcular el hashcode para la clave
  2. Calcular la posición hash % (arrayLength-1) donde se debe colocar el elemento (cubo número)
  3. Si intenta agregar un valor con una clave que ya se ha guardado en HashMap, entonces el valor se sobrescribe.
  4. De lo contrario, el elemento se agrega al cubo.

Si el cubo ya tiene al menos un elemento, se agrega uno nuevo y se coloca en la primera posición del cubo. Su campo next se refiere al elemento antiguo.

Supresión

  1. Calcular el hashcode para la clave dada
  2. Calcular el número de cubo hash % (arrayLength-1)
  3. Obtener una referencia al primer objeto de entrada en el bucket y por medio del método equals iterar sobre todas las entradas en el bucket dado. Eventualmente encontraremos el Entry correcto. Si no se encuentra un elemento deseado, return null
 57
Author: Sergii Shevchyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-06 20:42:39

Puede encontrar información excelente en http://javarevisited.blogspot.com/2011/02/how-hashmap-works-in-java.html

Para resumir:

HashMap funciona sobre el principio de hashing

Put (key, value): HashMap almacena los objetos key y value como Mapa.Entrada. Hashmap aplica hashcode (clave) para obtener el cubo. si hay una colisión ,HashMap usa LinkedList para almacenar el objeto.

Get (key): HashMap usa el hashcode del Objeto Key para encontrar fuera de la ubicación del cubo y luego llamar a las teclas.equals () método para identificar el nodo correcto en LinkedList y devolver el objeto de valor asociado para esa clave en Java HashMap.

 33
Author: Abhijit Gaikwad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-14 04:30:15

Aquí está una descripción aproximada del mecanismo de HashMap, para la versión Java 8, (podría ser ligeramente diferente de Java 6).


Estructuras de Datos

  • Tabla hash
    El valor Hash se calcula a través de hash() on key, y decide qué cubo de la tabla hash usar para una clave dada.
  • lista Enlazada (por separado)
    Cuando el número de elementos en un bucket es pequeño, una lista utilizar.
  • árbol Rojo-Negro
    Cuando la cantidad de elementos en un cubo es grande, se usa un árbol rojo-negro.

Clases (internas)

  • Map.Entry
    Representa una sola entidad en map, la entidad clave / valor.
  • HashMap.Node
    Versión de lista enlazada del nodo.

    Podría representar:

    • Un cubo de hash.
      Porque tiene una propiedad hash.
    • Un nodo en una lista enlazada, (así también head of linkedlist) .
  • HashMap.TreeNode
    Versión de árbol del nodo.

Campos (internos)

  • Node[] table
    La tabla bucket (cabeza de las listas enlazadas).
    Si un cubo no contiene elementos, entonces es null, por lo tanto solo toma espacio de una referencia.
  • Set<Map.Entry> entrySet Conjunto de entidades.
  • int size
    Número de entidades.
  • float loadFactor
    Indique qué tan llena está permitida la tabla hash, antes redimensionar.
  • int threshold
    El siguiente tamaño en el que cambiar el tamaño.
    Fórmula: threshold = capacity * loadFactor

Métodos (internos)

  • int hash(key)
    Calcular hash por clave.
  • ¿Cómo asignar hash a bucket?
    Utilice la siguiente lógica:

    static int hashToBucket(int tableSize, int hash) {
        return (tableSize - 1) & hash;
    }
    

Acerca de la capacidad

En la tabla hash, capacidad significa el conteo de cubos, podría ser get de table.length.
También podría calcularse a través de threshold y loadFactor, por lo tanto no hay necesidad de ser definido como un campo de clase.

Podría obtener la capacidad efectiva a través de: capacity()


Operaciones

  • Buscar entidad por clave.
    Primero encuentre el cubo por valor hash, luego haga un bucle en la lista vinculada o busque en el árbol ordenado.
  • Añadir entidad con clave.
    Primero encuentre el cubo de acuerdo con el valor hash de la clave.
    A continuación, intente encontrar el valor:
    • Si se encuentra, reemplace el valor.
    • De lo contrario, agregue un nuevo nodo al comienzo de la lista vinculada, o insertar en el árbol ordenado.
  • Redimensionar
    Cuando se alcance threshold, duplicará la capacidad de la tabla hash(table.length), luego realizará un re-hash en todos los elementos para reconstruir la tabla.
    Esto podría ser una operación costosa.

Rendimiento

  • get & put
    La complejidad temporal es O(1), porque:
    • Bucket se accede a través del índice de matriz, por lo tanto O(1).
    • La lista enlazada en cada cubo es de pequeña longitud, por lo que podría verse como O(1).
    • El tamaño del árbol también está limitado, porque extenderá la capacidad y re-hash cuando aumente el número de elementos, por lo que podría verlo como O(1), no como O(log N).
 21
Author: Eric Wang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-29 11:10:24

El hashcode determina qué bucket para el hashmap comprobar. Si hay más de un objeto en el cubo, se realiza una búsqueda lineal para encontrar qué elemento en el cubo es igual al elemento deseado (utilizando el método equals()).

En otras palabras, si tiene un hashcode perfecto, entonces el acceso a hashmap es constante, nunca tendrá que iterar a través de un bucket (técnicamente también tendría que tener bucks MAX_INT, la implementación de Java puede compartir algunos códigos hash en el mismo bucket para reducir las necesidades de espacio). Si tienes el peor hashcode (siempre devuelve el mismo número), entonces tu acceso a hashmap se vuelve lineal, ya que tienes que buscar en cada elemento del mapa (todos están en el mismo cubo) para obtener lo que quieres.

La mayoría de las veces un hashcode bien escrito no es perfecto, pero es lo suficientemente único como para darte un acceso más o menos constante.

 14
Author: Pace,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-27 13:34:13

Se equivoca en el punto tres. Dos entradas pueden tener el mismo código hash pero no ser iguales. Echa un vistazo a la implementación de HashMap.obtener del OpenJDK . Se puede ver que comprueba que los hashes son iguales y las teclas son iguales. Si el punto tres fuera verdadero, entonces no sería necesario verificar que las teclas son iguales. El código hash se compara antes de la clave porque la primera es una comparación más eficiente.

Si estás interesado en aprender un poco más acerca de esto, echa un vistazo al artículo de Wikipedia sobre Open Addressing collision resolution, que creo que es el mecanismo que utiliza la implementación de OpenJDK. Ese mecanismo es sutilmente diferente al enfoque de "cubo" que menciona una de las otras respuestas.

 11
Author: Leif Wickland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-07 06:52:26

Esta es una Pregunta muy Confusa para muchos de nosotros en las Entrevistas.Pero no es tan complejo.


sabemos

  • HashMap almacena par clave-valor en el mapa.Entrada (todos sabemos)

  • HashMap trabaja en el algoritmo de hashing y usa hashCode() y el método equals() en los métodos put() y get (). (incluso nosotros sabemos esto)

  • When we call put method by passing key-value pair, HashMap uses Key **hashCode()** with hashing to **find out the index** to store the key-value pair. (this is important)

  • The Entry is **stored in the LinkedList**, so if there are already existing entry, it uses **equals() method to check if the passed key already exists** (even this is important)

  • En caso afirmativo, sobrescribe el valor crea una nueva entrada y almacena esta entrada clave-valor.

  • Cuando llamamos a get methodpasando la Clave, nuevamente usa el hashCode() para encontrar el índiceen la matriz y luego usa el método equals() para encontrar la entrada correcta y devolver su valor. (ahora esto es obvio)

ESTA IMAGEN TE AYUDARÁ A ENTENDER:

Editar Septiembre de 2017: aquí vemos cómo el valor hash si se usa junto con igual después de encontrar cubo.

if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

}

introduzca la descripción de la imagen aquí

 7
Author: VedX,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-20 08:32:57
import java.util.HashMap;

public class Students  {
    String name;
    int age;

    Students(String name, int age ){
        this.name = name;
        this.age=age;
    }

    @Override
    public int hashCode() {
        System.out.println("__hash__");
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        System.out.println("__eq__");
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Students other = (Students) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    public static void main(String[] args) {

        Students S1 = new Students("taj",22);
        Students S2 = new Students("taj",21);

        System.out.println(S1.hashCode());
        System.out.println(S2.hashCode());

        HashMap<Students,String > HM = new HashMap<Students,String > (); 
        HM.put(S1, "tajinder");
        HM.put(S2, "tajinder");
        System.out.println(HM.size());
    }
}

Output:

__ hash __

116232

__ hash __

116201

__ hash __

__ hash __

2

Así que aquí vemos que si ambos objetos S1 y S2 tienen contenido diferente, entonces estamos bastante seguros de que nuestro método Hashcode anulado generará Hashcode diferente(116232,11601) para ambos objetos. AHORA, ya que hay diferentes códigos hash, por lo que ni siquiera se molestará en llamar al método IGUAL. Porque un Hashcode diferente GARANTIZA contenido DIFERENTE en un objeto.

    public static void main(String[] args) {

        Students S1 = new Students("taj",21);
        Students S2 = new Students("taj",21);

        System.out.println(S1.hashCode());
        System.out.println(S2.hashCode());

        HashMap<Students,String > HM = new HashMap<Students,String > (); 
        HM.put(S1, "tajinder");
        HM.put(S2, "tajinder");
        System.out.println(HM.size());
    }
}

Now lets change out main method a little bit. Output after this change is 

__ hash __

116201

__ hash __

116201

__ hash __

__ hash __

__ eq __

1
We can clearly see that equal method is called. Here is print statement __eq__, since we have same hashcode, then content of objects MAY or MAY not be similar. So program internally  calls Equal method to verify this. 


Conclusion 
If hashcode is different , equal method will not get called. 
if hashcode is same, equal method will get called.

Thanks , hope it helps. 
 4
Author: Tajinder Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-01 11:25:33

El mapa Hash funciona según el principio de hashing

El método HashMap get(Key k) llama al método hashCode en el objeto key y aplica hashValue devuelto a su propia función hash estática para encontrar una ubicación de cubo(matriz de respaldo) donde las claves y los valores se almacenan en forma de una clase anidada llamada Entry (Map.Entrada) . Así que usted ha llegado a la conclusión de que de la línea anterior que tanto la clave y el valor se almacena en el cubo como una forma de objeto de entrada . Así que pensando que solo el valor se almacena en el cubo no es correcto y no dará una buena impresión en el entrevistador .

  • Siempre que llamemos al método get( Key k ) en el objeto HashMap . Primero comprueba si la clave es nula o no . Tenga en cuenta que solo puede haber una clave nula en HashMap .

Si la clave es null , entonces las claves Null siempre se asignan a hash 0, por lo tanto index 0.

Si key no es null entonces , llamará a hashfunction en el objeto key , vea la línea 4 en el método anterior, es decir, key.hashCode (), así que después de la clave.hashCode() devuelve hashValue, la línea 4 se parece a

            int hash = hash(hashValue)

Y ahora ,aplica hashValue devuelto a su propia función de hashing .

Podríamos preguntarnos por qué estamos calculando el hashvalue de nuevo usando hash(hashValue). La respuesta es que defiende contra funciones hash de mala calidad.

Ahora se usa el hashvalue final para encontrar la ubicación del bucket en la que se almacena el objeto de Entrada . El objeto de entrada se almacena en el cubo como este (hash,key,value,bucketindex)

 2
Author: user217292,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-04 09:39:17

Cada objeto de entrada representa el par clave-valor. El campo siguiente se refiere a otro objeto de entrada si un bucket tiene más de 1 Entrada.

A veces puede suceder que los hashCodes para 2 objetos diferentes sean los mismos. En este caso, 2 objetos se guardarán en un cubo y se presentarán como LinkedList. El punto de entrada es objeto añadido más recientemente. Este objeto se refiere a otro objeto con el siguiente campo y así uno. La última entrada se refiere a null. Cuando se crea HashMap con el valor predeterminado constructor

La matriz se crea con un tamaño 16 y un equilibrio de carga predeterminado de 0.75.

introduzca la descripción de la imagen aquí

(Fuente)

 2
Author: Premraj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-16 12:02:43

No entraré en los detalles de cómo funciona HashMap, pero daré un ejemplo para que podamos recordar cómo funciona HashMap relacionándolo con la realidad.

Tenemos Clave, Valor ,hashCode y bucket.

Por algún tiempo, relacionaremos cada uno de ellos con lo siguiente:

  • Bucket- > Una Sociedad
  • hashCode - > Dirección de la sociedad (siempre única)
  • Valor - > Una Casa en la Sociedad
  • Clave -> Dirección de la casa.

Usando Map.get (clave):

Stevie quiere llegar a la casa de su amigo(Josse) que vive en una villa en una sociedad VIP, que sea JavaLovers Society. La dirección de Josse es su SSN (que es diferente para todos). Hay un índice mantenido en el que encontramos el nombre de la Sociedad basado en SSN. Este índice puede ser considerado como un algoritmo para encontrar el hashCode.

  • Nombre de la Sociedad SSN
  • 92313(Josse s) -- JavaLovers
  • 13214 Ang AngularJSLovers
  • 98080 -- JavaLovers
  • 53808 Bi BiologyLovers

  1. Este SSN(clave) primero nos da un hashCode(de la tabla índice) que no es más que el nombre de la Sociedad.
  2. Ahora, las casas múltiples pueden estar en la misma sociedad, por lo que el hashCode puede ser común.
  3. Supongamos que la Sociedad es común para dos casas, cómo vamos a identificar a qué casa vamos, sí, usando la clave (SSN)que no es más que la dirección de la Casa

Usando Asignar.put (clave,Valor)

Esto encuentra una sociedad adecuada para este Valor encontrando el hashCode y luego el valor se almacena.

Espero que esto ayude y está abierto a modificaciones.

 1
Author: Prashant K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-17 06:49:32

En una forma resumida de Cómo funciona HashMap en java?

HashMap funciona según el principio de hashing, tenemos el método put() y get() para almacenar y recuperar objetos de HashMap. Cuando pasamos la clave y el valor al método put () para almacenar en HashMap, utiliza el método key object hashcode () para calcular el hashcode y al aplicar el hashing en ese hashcode, identifica la ubicación del cubo para almacenar el objeto value. Al recuperar, utiliza el método key object equals para averiguar corregir el par de valor de clave y el objeto de valor devuelto asociado a esa clave. HashMap utiliza la lista enlazada en caso de colisión y el objeto se almacenará en el siguiente nodo de la lista enlazada. También HashMap almacena tanto clave+valor tupla en cada nodo de la lista vinculada.

 1
Author: JAVA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-17 03:58:34

Dos objetos son iguales, implica que tienen el mismo hashcode, pero no viceversa{[16]]}

Actualización de Java 8 en HashMap -

Usted hace esta operación en su código -

myHashmap.put("old","key-value-pair");
myHashMap.put("very-old","old-key-value-pair");

Entonces, supongamos que su hashcode devuelto para ambas claves "old" y "very-old" es el mismo. Entonces qué pasará.

myHashMap es un HashMap, y supongamos que inicialmente no especificó su capacidad. Así que la capacidad predeterminada según Java es 16. Así que ahora tan pronto como inicializaste hashmap usando la nueva palabra clave, creó 16 buckets. ahora, cuando ejecutó la primera declaración -

myHashmap.put("old","key-value-pair");

Entonces hashcode para "old" se calcula, y debido a que el hashcode podría ser un entero muy grande también, por lo tanto, java internamente hizo esto - (hash es hashcode aquí y >>> es desplazamiento derecho)

hash XOR hash >>> 16

Así que para dar una imagen más grande devolverá algún índice, que estaría entre 0 y 15. Ahora su par de valor de clave "old" y "key-value-pair" se convertirían en la instancia de clave y valor del objeto de entrada variable. y, a continuación, este objeto de entrada se almacenará en el cubo, o se puede decir que en un índice particular, este objeto de entrada sería almacenado.

FYI - Entry es una clase en Map interface - Map.Entrada, con esta firma/definición

class Entry{
          final Key k;
          value v;
          final int hash;
          Entry next;
}

Ahora cuando ejecuta la siguiente instrucción -

myHashmap.put("very-old","old-key-value-pair");

Y "very-old" da el mismo hashcode que "old", por lo que este nuevo par de valores de clave se envía de nuevo al mismo índice o al mismo bucket. Pero dado que este cubo no está vacío, entonces el next la variable del objeto de entrada se utiliza para almacenar este nuevo par de valores de clave.

Y esto se almacenará como lista vinculada para cada objeto que tenga el mismo hashcode, pero se especifica un TRIEFY_THRESHOLD con el valor 6. así que después de que esto llegue, la lista enlazada se convierte en el árbol balanceado(árbol rojo-negro) con el primer elemento como la raíz.

 1
Author: theanubhava,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-16 17:27:23

Como se dice, una imagen vale 1000 palabras. Yo digo: un código es mejor que 1000 palabras. Aquí está el código fuente de HashMap. Método Get:

/**
     * Implements Map.get and related methods
     *
     * @param hash hash for key
     * @param key the key
     * @return the node, or null if none
     */
    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

Así que queda claro que hash se usa para encontrar el "bucket" y el primer elemento siempre se comprueba en ese bucket. Si no, entonces equals de la clave se utiliza para encontrar el elemento real en la lista vinculada.

Veamos el método put():

  /**
     * Implements Map.put and related methods
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to put
     * @param onlyIfAbsent if true, don't change existing value
     * @param evict if false, the table is in creation mode.
     * @return previous value, or null if none
     */
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

Es un poco más complicado, pero queda claro que el nuevo elemento es poner en la pestaña en la posición calculada en base a hash:

i = (n - 1) & hash aquí i es el índice donde se pondrá el nuevo elemento (o es el "bucket"). n es el tamaño de la matriz tab (matriz de "cubos").

Primero, se intenta ponerlo como el primer elemento de ese "cubo". Si ya hay un elemento, añada un nuevo nodo a la lista.

 0
Author: ACV,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-22 20:40:21

Va a ser una respuesta larga, toma una copa y sigue leyendo {{[14]]}

El hash consiste en almacenar un par clave-valor en la memoria que se puede leer y escribir más rápido. Almacena las claves en una matriz y los valores en una lista de enlaces .

Digamos que quiero almacenar 4 pares de valores clave -

{
“girl” => “ahhan” , 
“misused” => “Manmohan Singh” , 
“horsemints” => “guess what”, 
“no” => “way”
}

Así que para almacenar las claves necesitamos una matriz de 4 elementos . Ahora, ¿cómo mapeo una de estas 4 claves a 4 índices de matriz (0,1,2,3)?

Así que java encuentra el hashCode de las claves individuales y mapearlos a un índice de matriz particular . Fórmulas de Hashcode is -

1) reverse the string.

2) keep on multiplying ascii of each character with increasing power of 31 . then add the components .

3) So hashCode() of girl would be –(ascii values of  l,r,i,g are 108, 114, 105 and 103) . 

e.g. girl =  108 * 31^0  + 114 * 31^1  + 105 * 31^2 + 103 * 31^3  = 3173020

Hash y chica !! Sé lo que estás pensando. Tu fascinación por ese dúo salvaje podría hacerte perder algo importante .

¿Por qué Java lo multiplica por 31 ?

Es porque, 31 es un primo impar en la forma 2^5 – 1 . Y primo impar reduce la posibilidad de colisión Hash

Ahora cómo se asigna este código hash a una matriz índice?

La respuesta es , Hash Code % (Array length -1). Así que “girl” se asigna a (3173020 % 3) = 1 en nuestro caso . que es el segundo elemento de la matriz .

Y el valor "ahhan" se almacena en una lista de enlaces asociada con el índice de matriz 1 .

HashCollision - Si intenta encontrar hasHCode de las claves “misused” y “horsemints” usando las fórmulas descritas anteriormente, verá que ambas nos dan lo mismo 1069518484. Whooaa !! lección aprendida -

2 objetos iguales deben tener el mismo hashCode pero no no es garantía si el hashCode coincide entonces los objetos son iguales . Por lo que debe almacenar ambos valores corresponden a "mal uso" y "horsemints" al cubo 1 (1069518484 % 3) .

Ahora el mapa hash se ve como -

Array Index 0 –
Array Index 1 - LinkedIst (“ahhan” , “Manmohan Singh” , “guess what”)
Array Index 2 – LinkedList (“way”)
Array Index 3 – 

Ahora, si algún cuerpo trata de encontrar el valor de la clave “horsemints” , java rápidamente encontrará la etiqueta de la misma , el módulo de e iniciar la búsqueda del valor en el LinkedList correspondiente index 1 . Así que de esta manera no necesitamos buscar todos los índices de matriz 4 por lo tanto, el acceso a los datos es más rápido.

Pero , espera , un segundo . hay 3 valores en ese índice de matriz correspondiente a LinkedList 1, ¿cómo descubre cuál fue el valor de la clave "horsemints" ?

En realidad mentí, cuando dije HashMap sólo almacena valores en LinkedList .

Almacena ambos pares de valores clave como entrada de mapa. Así que en realidad el mapa se ve así .

Array Index 0 –
Array Index 1 - LinkedIst (<”girl” => “ahhan”> , <” misused” => “Manmohan Singh”> , <”horsemints” => “guess what”>)
Array Index 2 – LinkedList (<”no” => “way”>)
Array Index 3 – 

Ahora puede ver Mientras atraviesa la lista de enlaces correspondiente para ArrayIndex1 realmente compara la clave de cada entrada a de esa lista de enlaces a "horsemints" y cuando encuentra una solo devuelve el valor de la misma .

Espero que te hayas divertido mientras lo lees:)

 -1
Author: sapy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-20 11:12:26