Рубрики
Без рубрики

Как HashMap работает внутри java : Подход к отладке

Наиболее распространенными вопросами интервью являются “Как работает HashMap в java”, “Как получить и поместить метод HashMap w… С тегами java, коллекции, хэш-карта, интервью.

Наиболее распространенные вопросы интервью: “Как работает HashMap в java “, “Как получить и поместить метод HashMap работает внутренне”. Здесь я пытаюсь объяснить внутреннюю функциональность на простом примере. HashMap – одна из наиболее часто используемых коллекций в java . Вместо того, чтобы изучать теорию, мы начнем сначала с примера, чтобы вы лучше поняли, а затем мы увидим, как работают функции get и put в java.

Давайте возьмем очень простой пример. У меня есть класс страны, мы собираемся использовать объект класса страны в качестве ключа и его заглавное имя (строка) в качестве значения. Приведенный ниже пример поможет вам понять, как эти пары значений ключей будут храниться в hashmap.

1. Country.java

package org.arpit.java2blog;
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;
    }

    // If length of name in country object is even then return 31(any random number) and if odd then return 95(any random number).
    // This is not a good practice to generate hashcode as below method but I am doing so to give better and easy understanding of hashmap.
    @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;
    }

}
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 countryCapitalMap=new HashMap();  
        countryCapitalMap.put(india,"Delhi");  
        countryCapitalMap.put(japan,"Tokyo");  
        countryCapitalMap.put(france,"Paris");  
        countryCapitalMap.put(russia,"Moscow");  

        Iterator countryCapitalIter=countryCapitalMap.keySet().iterator();//put debug point at this line  
        while(countryCapitalIter.hasNext())  
        {  
            Country countryObj=countryCapitalIter.next();  
            String capital=countryCapitalMap.get(countryObj);  
            System.out.println(countryObj.getName()+"----"+capital);  
        }  
    }  


}
    1. Существует массив записей[], называемый таблицей, который имеет размер 16.
    2. В этой таблице хранится объект класса записи. Класс HashMap имеет внутренний класс, называемый Entry. Эта запись имеет ключевое значение в качестве переменной экземпляра. Давайте посмотрим структуру структуры входа в класс.
static class Entry implements Map.Entry
{
        final K key;
        V value;
        Entry next;
        final int hash;
        ...//More code goes here
}
  1. Всякий раз, когда мы пытаемся поместить любую пару значений ключа в hashmap, объект класса ввода создается для значения ключа, и этот объект будет сохранен в вышеупомянутой записи[](таблица). Теперь вам, должно быть, интересно, где будет храниться выше созданный объект ввода (точное положение в таблице). Ответ заключается в том, что хэш-код вычисляется для ключа путем вызова метода Hascode(). Этот хэш-код используется для вычисления индекса для приведенной выше таблицы записей[].
  2. Теперь, если вы видите индекс массива 10 на приведенной выше диаграмме, у него есть объект записи с именем HashMap$Entry.
  3. Мы поместили 4 значения ключа в hashmap, но, похоже, их всего 2!!!! Это связано с тем, что если два объекта имеют одинаковый хэш-код, они будут храниться в одном и том же индексе. Теперь возникает вопрос, как это сделать? Он хранит объекты в виде связанного списка (логически).
Hashcode for Japan = 95 as its length is odd.
Hashcode for India =95 as its length is odd
HashCode for Russia=31 as its length is even.
HashCode for France=31 as its length is even.

На приведенной ниже диаграмме будет четко объяснена концепция связанного списка.

Итак, теперь, если вы хорошо разбираетесь в структуре хэш-карты, давайте рассмотрим метод put и get.

Поставь

Давайте посмотрим на реализацию метода put:

       /**
         * Associates the specified value with the specified key in this map. If the
         * map previously contained a mapping for the key, the old value is
         * replaced.
         *
         * @param
 key
         *            key with which the specified value is to be associated
         * @param
 value
         *            value to be associated with the specified key
         * @return the previous value associated with key, or null
         *         if there was no mapping for key. (A null return
         *         can also indicate that the map previously associated
         *         null with key.)
         */
        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 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;
        }
  1. Ключевой объект проверяется на значение null. Если ключ равен нулю, то он будет сохранен в таблице[0], потому что хэш-код для null всегда равен 0.
  2. Вызывается метод хэш-кода ключевого объекта() и вычисляется хэш-код. Этот хэш-код используется для поиска индекса массива для хранения объекта ввода. Иногда может случиться так, что эта функция хэш-кода плохо написана, поэтому разработчик JDK поставил другую функцию под названием hash(), которая принимает в качестве аргумента значение хэша, вычисленное выше. Если вы хотите узнать больше о функции hash(), вы можете обратиться к hash и индекс для метода в hashmap .
  3. Индекс для (хэш, таблица.длина) используется для вычисления точного индекса в массиве таблиц для хранения объекта ввода.
  4. Как мы видели в нашем примере, если два ключевых объекта имеют одинаковый хэш-код (который известен как столкновение ), то он будет сохранен в виде списка ссылок. Итак, здесь мы пройдемся по нашему связанному списку.

    • Если в этом индексе нет элемента, который мы только что вычислили, то он напрямую поместит наш объект ввода в этот индекс.
    • Если в этом индексе присутствует элемент, он будет повторяться до тех пор, пока не получит значение Entry->next как null.
    • Что делать, если мы снова вводим тот же ключ, логически он должен заменить старое значение. Да, это будет сделано. Во время итерации он проверит равенство ключей, вызвав метод equals()( ключ.равно (k) ), если этот метод возвращает значение true, то он заменяет объект значения объектом значения текущей записи.
    • Если он не нашел дубликат ключа, текущий объект записи станет первым узлом в списке ссылок, а текущая запись -> далее станет существующим первым узлом в этом индексе.

Возьми

/**
     * Returns the value to which the specified key is mapped, or {@code null}
     * if this map contains no mapping for the key.
     *
     *
     * More formally, if this map contains a mapping from a key {@code k} to a
     * value {@code v} such that {@code (key==null ? k==null :
     * key.equals(k))}, then this method returns {@code v}; otherwise it returns
     * {@code null}. (There can be at most one such mapping.)
     *
     *
     * A return value of {@code null} does not necessarily indicate that
     * the map contains no mapping for the key; it's also possible that the map
     * explicitly maps the key to {@code null}. The {@link
 #containsKey
     * containsKey} operation may be used to distinguish these two cases.
     *
     * @see #put(Object, Object)
     */
    public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry 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;
    }

Поскольку вы получили представление о функциональности hashmap. Так что понять функциональность get довольно просто. Если вы передадите какой-либо ключ, чтобы получить объект значения из hashmap.

  1. Ключевой объект проверяется на значение null. Если ключ равен нулю, то будет возвращено значение объекта, находящегося в таблице[0].
  2. Вызывается метод хэш-кода ключевого объекта() и вычисляется хэш-код.
  3. Индекс для (хэш, таблица.длина) используется для вычисления точного индекса в массиве таблиц с использованием сгенерированного хэш-кода для получения объекта ввода.
  4. После получения индекса в массиве таблиц он будет перебирать связанный список и проверять равенство ключей, вызывая метод equals(), и если он возвращает значение true, то возвращает значение объекта ввода, иначе возвращает значение null.

Ключевые моменты, которые нужно запомнить:

  • У HashMap есть внутренний класс под названием Entry, в котором хранятся пары ключ-значение.
  • Выше объект записи хранится в записи[](массив), называемой таблицей
  • Индекс таблицы логически называется корзиной, и в нем хранится первый элемент списка ссылок
  • Ключевой объект хэш-код () используется для поиска корзины этого объекта ввода.
  • Если два ключевых объекта имеют одинаковый хэш-код, они будут помещены в одно и то же ведро массива таблиц.
  • Метод equals() ключевого объекта используется для обеспечения уникальности ключевого объекта.
  • Значение объекта equals() и метод hashcode() вообще не используются

Первоначально опубликовано в Java2blog с заголовком Как работает HashMap в java

Вам также может понравиться

Оригинал: “https://dev.to/arpitmandliya/how-hashmap-works-internally-in-java-a-debug-approach-58fn”