JavaRush /Blog Java /Random-ES /¿Cómo funciona HashMap en Java?
gnev
Nivel 24

¿Cómo funciona HashMap en Java?

Publicado en el grupo Random-ES
¿Cómo funciona HashMap en Java?  - 1Muy a menudo en las entrevistas hacen preguntas como "¿ Cómo funciona HashMap en Java?" ”, “¿Cuál es el mecanismo interno de cómo funcionan los métodos geten putHashMap?”. Aquí intentaré explicar la funcionalidad interna usando un ejemplo simple. Sin entrar en demasiada teoría, comenzaremos con un ejemplo para que puedas comprender mejor y luego ver cómo funcionan los métodos gettambién puten Java . Tomemos un ejemplo muy simple. Tenemos una clase Country(“país” en inglés), usaremos el objeto de clase Countrycomo clave y el nombre de la capital de este país como valor. A continuación se muestra un ejemplo que nos ayudará a comprender cómo se almacenará un par clave-valor en un mapa hash.

1. País.java

package org.arpit.javapostsforlearning;
public class Country {

 String name;
 long population;

 public Country(String name, long population) {
  super();
  this.name = name;
  this.population = population;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public long getPopulation() {
  return population;
 }
 public void setPopulation(long population) {
  this.population = population;
 }

 // если длина имени в un objetoе Country - четное число,
 // то возвращаем 31(любое случайное число), а если нечетное - 95 (любое случайное число).
 // указанный ниже метод - это не самый лучший способ генерации хеш-códigoа,
 // но мы воспользуемся им для более четкого понимания хеш-карт.

 @Override
 public int hashCode() {
  if(this.name.length()%2==0)
   return 31;
  else
   return 95;
 }
 @Override
 public boolean equals(Object obj) {

  Country other = (Country) obj;
   if (name.equalsIgnoreCase((other.name)))
   return true;
  return false;
 }
}
Si quieres entender y aprender más sobre métodos hashcodee iguales, puedes seguir este enlace .

2. HashMapStructure.java (clase principal)

import java.util.HashMap;
import java.util.Iterator;

public class HashMapStructure {

    /**
     * @author Arpit Mandliya
     */
    public static void main(String[] args) {

        Country india=new Country("India",1000);
        Country japan=new Country("Japan",10000);

        Country france=new Country("France",2000);
        Country russia=new Country("Russia",20000);

        HashMap<country,string> countryCapitalMap=new HashMap<country,string>();
        countryCapitalMap.put(india,"Delhi");
        countryCapitalMap.put(japan,"Tokyo");
        countryCapitalMap.put(france,"Paris");
        countryCapitalMap.put(russia,"Moscow");

        Iterator<country> countryCapitalIter=countryCapitalMap.keySet().iterator();//установите
        //debug-точку на этой строке(23)
        while(countryCapitalIter.hasNext())
        {
            Country countryObj=countryCapitalIter.next();
            String capital=countryCapitalMap.get(countryObj);
            System.out.println(countryObj.getName()+"----"+capital);
            }
        }
}
Ahora establezca el punto de interrupción en la línea 23 y ejecute ejecutar -> depurar como-> aplicación java (nota del traductor, válida para Eclipse). El programa detendrá la ejecución en la línea 23, luego haga clic derecho en countryCapitalMap y seleccione mirar . Verá una tabla como esta: ¿Cómo funciona HashMap en Java?  - 2Aquí vemos lo siguiente:
  1. Hay una serie Entry[]de 16 celdas denominadas table;

  2. Esta matriz almacena objetos de la clase Entry. La clase HashMaptiene una clase interna: Entry. Y las instancias de esta clase son pares clave-valor. Echemos un vistazo a la estructura de clases Entry:

  3. static class Entry implements Map.Entry
            {
                    final K key;
                    V value;
                    Entry next;
                    final int hash;
                    ...//продолжение códigoа
            }
  4. Cada vez que intentamos crear un par clave-valor en un mapa hash, se creará un objeto de clase para ese par Entryy se almacenará en la tabla anterior Entry[]. Y ahora debería preguntarse dónde exactamente en esta tabla se escribirá este objeto (en qué celda). Para una clave en un par clave-valor, se calcula un código hash utilizando el archivo hashcode(). Y este código hash se utiliza para calcular el número de celda de la tabla Entry[];

  5. Ahora, si observa la celda 10 de la tabla, verá un objeto de clase Entryllamado HashMap$Entry;

  6. Agregamos 4 pares clave-valor, ¡pero solo hay 2 en la matriz! Esto se debe a que si 2 objetos tienen el mismo código hash, se almacenarán en la misma celda. ¿Pero cómo? Los objetos se almacenarán como una lista vinculada ( LinkedList).
Así es como se calculará el código hash para nuestros pares clave-valor.
Hashcode for Japan = 95 так Cómo длина слова Japan имеет нечетное количество букв.
Hashcode for India = 95 так Cómo длина слова India имеет нечетное количество букв.
HashCode for Russia = 31 так Cómo длина слова Russia имеет четное количество букв.
HashCode for France = 31 так Cómo длина слова France имеет четное количество букв.
La siguiente figura explicará la idea de una lista vinculada: ¿Cómo funciona HashMap en Java?  - 3ahora que ya comprende la estructura de los mapas hash, pasemos a los métodos puty get.

Poner:

Veamos cómo se utiliza este método:
/**
  * Метод связывает указанное significado с указанным ключом в данной хэш-карте. Если
  * карта до этого уже содержала некоторое significado, соответствующее этому ключу,
  * то старое significado заменяется на указанное.
  * @param key
  *            ключ, с которым связывается указанное significado
  * @param value
  *            significado, связываемое с указанным ключом
  * @возвращает significado связанное с <tt>ключом</tt>, o <tt>null</tt>,
  *         если ниCómoое significado не соответствует <tt>ключу</tt>. ( Возврат <tt>null</tt>
  *         может так же говорить о том, что в карте заведомо <tt>null</tt> был связан с
  *         <tt>ключом</tt>.)
  */
 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;
 }
Ahora intentemos entender este código paso a paso:
  1. Comprobamos la keyigualdad del objeto null. Si es así, entonces el objeto keyse almacenará en la ubicación table[0]porque el código hash nulles siempre 0;

  2. A continuación, llamamos al keymétodo del objeto hashcode(), que calculará su código hash. Este código hash se utiliza para determinar la celda de la matriz donde se almacenará el objeto de clase Entry. A veces sucede que esta función hashcodeno está escrita con mucha habilidad, por lo que los desarrolladores de JDK crearon una función diferente, hash()que toma como argumento el código hash previamente calculado. Si estás interesado en leer más sobre esta función, puedes seguir el enlace ;

  3. indexFor(hash,table.length)se utiliza para definir una celda específica en la matriz tableen la que se definirá un objeto de clase para ser almacenado Entry;

  4. Como vimos en nuestro ejemplo, si dos objetos keytienen el mismo código hash (esta situación se conoce como colisión), se almacenarán en forma de lista vinculada. Por lo tanto, en esta etapa iteramos nuestra lista:

    • si la celda recién calculada está vacía, el objeto de clase Entryse guardará directamente en esta celda;

    • si esta celda ya contiene algún objeto, se itera hasta el elemento cuyo campo es nextigual a null. Después de esto, nuestro objeto de clase Entrypasa a ser el siguiente en la lista;

    • ¿Qué pasa si volvemos a agregar el mismo objeto key? Lógicamente, debería reemplazar el valor anterior. Sí, así será. Durante la iteración, las claves se compararán utilizando el método equals()( key.equals(k)). Si el resultado es verdadero, entonces el valor anterior será reemplazado por el valor del objeto actual Entry.

Conseguir:

Ahora echemos un vistazo a la aplicación del método. conseguir
/**
  * devoluciones significado, которое соответствует указанному ключу, o {@code null}, если
  * данная карта не содержит пары с указанным ключом.
  *
  *
  * <p>
  * Более точно, если в данной карте содержится такой ключ {@code k}
  * с соответствующим ему significadoм {@code v}, что {@code (key==null ? k==null : key.equals(k))},
  * то метод возвращает {@code v}; в противном случае возвращается {@code null}.
  * (может быть не более одной такой пары)
  *
  * </p><p>
  * Возвращенное significado {@code null} не <i>обязательно</i> говорит о том, что
  * в карте нет пары с таким указанным ключом; а возможно, что в карте однозначно
  * указано соответствие этого ключа со significadoм {@code null}.
  * Можно воспользоваться операцией {@link #containsKey containsKey}, чтобы
  * отличить эти два случая
  * @see #put(Object, Object)
  */
 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;
 }
Ahora que comprende cómo funciona el método put en hashmaps, comprender cómo funciona el método put es getmuy simple. Cuando pasas cualquier clave a un método para obtener un valor de un mapa hash:
  1. Un objeto Ekey se prueba para determinar la igualdad null. Si es así, se devolverá el valor del objeto almacenado en la celda table[0];

  2. El objeto clave tiene un método llamado hashcode()que calcula el código hash;

  3. indexFor(hash,table.length)se utiliza para determinar una celda de matriz específica tablede la cual tomar un objeto de clase Entry;

  4. Después de recibir el número de celda de la matriz, tablerecorrerá la lista y comparará las claves utilizando el método equals(). Si el resultado es verdadero, se devolverá el valor del objeto Entry; de lo contrario, - null.

Cosas para recordar:

  • La clase HashMaptiene una clase interna Entryque almacena pares clave-valor;

  • Los objetos de la clase Entryse almacenan en una matriz Entry[ ]llamada table;

  • Una celda de matriz se llama depósito y almacena el primer elemento de una lista vinculada;

  • El método hashcode()de objeto keyse utiliza para encontrar el depósito de este objeto de clase Entry;

  • Si las claves de dos objetos tienen el mismo código hash, se almacenarán en el mismo depósito de matriz table;

  • El método equals()de un objeto keyse utiliza para confirmar su unicidad;

  • No se utilizan métodos equals()ni hashcode()objetos valueen absoluto.

Fuente
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION