Как Java HashMap обрабатывает различные объекты с одним и тем же хэш-кодом?

как я понимаю, я думаю:

  1. совершенно законно, чтобы два объекта имели один и тот же хэш-код.
  2. если два объекта равны (используя метод equals ()), то они имеют один и тот же хэш-код.
  3. если два объекта не равны, то они не могут иметь одинаковый хэш-код

Я прав?

Теперь, если я прав, у меня есть следующий вопрос: The HashMap внутренне использует хэш-код объекта. Так что если два объекты могут иметь один и тот же хэш-код, тогда как может HashMap отслеживать, какой ключ он использует?

может кто-нибудь объяснить, как HashMap внутренне использует хэш-код объекта?

16 ответов


hashmap работает следующим образом (это немного упрощено, но иллюстрирует основной механизм):

он имеет несколько "ведер", которые он использует для хранения пар ключ-значение. Каждое ведро имеет уникальный номер-это то, что идентифицирует ведро. Когда вы помещаете пару ключ-значение в карту, hashmap будет смотреть на хэш-код ключа и хранить пару в ведре, идентификатором которого является хэш-код ключа. Например, хэш-код ключа 235 -> пара хранится в ведре номер 235. (Обратите внимание, что в одном ведре может храниться более одной пары ключ-значение).

когда вы ищете значение в hashmap, давая ему ключ, он сначала посмотрит на хэш-код ключа, который вы дали. Затем hashmap будет смотреть в соответствующее ведро, а затем он будет сравнивать ключ, который вы дали с ключами всех пар в ведре, сравнивая их с equals().

теперь вы можете видеть, как это очень эффективно для поиска пары ключ-значение на карте: по хэш-коду ключа hashmap сразу знает, в каком ведре искать, так что ему нужно только протестировать то, что находится в этом ведре.

глядя на вышеуказанный механизм, вы также можете увидеть, какие требования необходимы на hashCode() и equals() методы клавиш:

  • если два ключа совпадают (equals() возвращает true когда вы сравниваете их), их hashCode() метод должен возвращать то же число. Если ключи нарушают это, тогда ключи, которые равны, могут храниться в разных ведрах, и hashmap не сможет найти пары ключ-значение (потому что он будет выглядеть в одном ведре).

  • если два ключа разные, то не имеет значения, являются ли их хэш-коды одинаковыми или нет. Они будут храниться в одном ведре, если их хэш-коды одинаковы, и в этом случае hashmap будет использовать equals() чтобы отличить их друг от друга.


ваше третье утверждение неверно.

совершенно законно, чтобы два неравных объекта имели один и тот же хэш-код. Он используется HashMap как "фильтр первого прохода", чтобы карта могла быстро найти возможно записи с указанным ключом. Ключи с тем же хэш-кодом затем проверяются на равенство с указанным ключом.

вам не нужно требование, чтобы два неравных объекта не могли иметь один и тот же хэш-код, иначе это ограничило бы вам 232 возможные объекты. (Это также означает, что разные типы не могут даже использовать поля объекта для генерации хэш-кодов, поскольку другие классы могут генерировать тот же хэш.)


HashMap structure diagram

HashMap массив Entry объекты.

считают HashMap как просто массив объектов.

посмотрите, что это Object - это:

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

каждого Entry объект представляет собой пару ключ-значение. Поле next относится к другой Entry объект, если ведро имеет более одного Entry.

иногда может случиться, что хэш-коды для 2 разных объектов одинаковы. В данном случае два объекты будут сохранены в одном ведре и будут представлены в виде связанного списка. Точка входа-это недавно добавленный объект. Этот объект относится к другому объекту с next поле и так далее. Последняя запись относится к null.

при создании HashMap с конструктором по умолчанию

HashMap hashMap = new HashMap();

массив создается с размером 16 и балансом нагрузки по умолчанию 0.75.

добавление новой пары ключ-значение

  1. рассчитать хэш-код для ключа
  2. вычислить позицию hash % (arrayLength-1) где элемент должен быть помещен (сегмент)
  3. если вы попытаетесь добавить значение с ключом, который уже был сохранен в HashMap, затем значение перезаписывается.
  4. в противном случае элемент добавляется в ведро.

если ведро уже имеет хотя бы один элемент, добавляется новый и помещается в первую позицию ведра. Его next поле относится к старому элемент.

удаление

  1. вычислить хэш-код для данного ключа
  2. вычислить номер ведра hash % (arrayLength-1)
  3. получите ссылку на первый объект записи в ведре и с помощью метода equals повторите все записи в данном ведре. В конце концов, мы найдем правильный Entry. Если нужный элемент не найден, возвращает null

вы можете найти превосходную информацию на http://javarevisited.blogspot.com/2011/02/how-hashmap-works-in-java.html

Подведем Итоги:

HashMap работает по принципу хэширования

put (ключ, значение): HashMap хранит как ключ, так и объект значения как карту.Вхождение. Частности, применяется хэш-код(ключ), чтобы получить ведро. если есть столкновение, HashMap использует LinkedList для хранения объекта.

get (ключ): HashMap использует хэш-код ключевого объекта, чтобы узнать местоположение ведра, а затем вызвать ключи.метод equals () для идентификации правильного узла в LinkedList и возврата связанного объекта значения для этого ключа в Java HashMap.


вот приблизительное описание для Java 8 версия (это может немного отличаться от Java 6).


структуры данных

  • хэш-таблицы
    Значение хэша рассчитывается через hash() on key, и он решает, какое ведро хэш-таблицы использовать для данного ключа.
  • список ссылок (одиночно)
    Когда граф элементы в ведре небольшие, используется односвязный список.
  • красно-черное дерево
    Когда количество элементов в ведре велико, используется красно-черное дерево.

классы (внутри)

  • Map.Entry
    Представлять одну сущность на карте, сущность ключ/значение.
  • HashMap.Node
    Связанный список версия узла.

    это может представляем:

    • хэш-ведро.
      Потому что у него есть свойство hash.
    • узел однонаправленного списка, (таким образом также руководитель linkedlist).
  • HashMap.TreeNode
    Древовидная версия узла.

поля (внутри)

  • Node[] table
    Таблица ведро, (глава связанных списков).
    Если ведро не содержит элементов, то это null, таким образом, занимает только пространство ссылки.
  • Set<Map.Entry> entrySet Набор сущностей.
  • int size
    Количество объектов.
  • float loadFactor
    Перед изменением размера укажите, насколько заполнена хэш-таблица.
  • int threshold
    Следующий размер в размер.
    Формула:threshold = capacity * loadFactor

методы (внутри)

  • int hash(key)
    Вычислить хэш по ключ.
  • как отобразить хэш в ведро?
    Используйте следующую логику:

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

о емкости

в хэш-таблице емкость означает количество ведер, его можно получить из table.length.
Также может быть рассчитан через threshold и loadFactor, таким образом, нет необходимости определять как поле класса.

смогл получить эффективную емкость через: capacity()


операции

  • найти объект по ключу.
    Сначала найдите ведро по хэш-значению, затем цикл связанный список или поиск отсортированного дерева.
  • Добавить объект с ключом.
    Сначала найдите ведро в соответствии с хэш-значением ключа.
    Затем попробуйте найти значение:
    • если найдено, замените значение.
    • в противном случае добавьте новый узел в начале связанного списка или вставьте в сортировку дерево.
  • изменение размера
    Когда threshold достигнуто, удвоит емкость hashtable(table.length), затем выполните повторный хэш для всех элементов, чтобы перестроить таблицу.
    Это может быть дорогостоящая операция.

производительность

  • get & put
    Сложность времени O(1), потому что:
    • ведро доступно через индекс массива, таким образом O(1).
    • связанный список в каждом ведре небольшая длина, таким образом, может рассматриваться как O(1).
    • размер дерева также ограничен, потому что расширит емкость и повторный хэш, когда количество элементов увеличится, поэтому его можно просмотреть как O(1), а не O(log N).

хэш-код определяет, какое ведро для проверки хэш-карты. Если в ведре больше одного объекта, выполняется линейный поиск, чтобы найти, какой элемент в ведре равен желаемому элементу (используя equals()) метод.

другими словами, если у вас есть идеальный хэш-код, то доступ к hashmap постоянен, вам никогда не придется перебирать ведро (технически вам также придется иметь ведра MAX_INT, реализация Java может делиться несколькими хэш-кодами в такое же ведро, котор нужно отрезать вниз на требованиях к космоса). Если у вас худший хэш-код (всегда возвращает одно и то же число), то ваш доступ к hashmap становится линейным, так как вам нужно искать каждый элемент на карте (все они находятся в одном ведре), чтобы получить то, что вы хотите.

большую часть времени хорошо написано хэш-код не идеален, но достаточно уникальный, чтобы дать вам более или менее постоянный доступ.


вы ошибаетесь в пункте три. Две записи могут иметь один и тот же хэш-код, но не быть равными. Взгляните на реализацию HashMap.получить от OpenJdk. Вы можете видеть, что он проверяет, что хэши равны и ключи равны. Если бы точка три была истинной, то не было бы необходимости проверять, что ключи равны. Хэш-код сравнивается перед ключом, потому что первый является более эффективным сравнением.

Если вы заинтересованы в изучении немного больше об этом, взгляните на статью Википедии на открыть решении столкновение, который, я считаю, является механизмом, который использует реализация OpenJdk. Этот механизм тонко отличается от подхода "ведра", который упоминается в одном из других ответов.


Это самый запутанный вопрос для многих из нас в интервью.Но это не так сложно.


мы знаем!--4-->

  • хранилище HashMap магазинах пара в карту.Запись (мы все знаем)

  • HashMap работает по алгоритму хэширования и использует метод hashCode() и equals() в методах put() и get (). (даже мы это знаем)

  • 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)

  • если да, он перезаписывает значение else он создает новую запись и сохраняет эту запись значения ключа.

  • когда мы называем метод GET передавая ключ, он снова использует hashCode (), чтобы найти индекс в массиве, а затем используйте equals() метод, чтобы найти правильную запись и вернуть его стоимость. (теперь это очевидно)

ЭТО ИЗОБРАЖЕНИЕ ПОМОЖЕТ ВАМ ПОНЯТЬ:

Изменить Сентябрь 2017: здесь мы видим, как хэш-значение используется вместе с equals после того, как мы найдем ведро.

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

}

enter image description here


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

Итак, здесь мы видим, что если оба объекта S1 и S2 имеют разное содержимое, то мы уверены, что наш переопределенный метод хэш-кода будет генерировать другой хэш-код(116232,11601) для обоих объектов. Теперь, поскольку есть разные хэш-коды, поэтому он даже не будет беспокоиться о вызове метода EQUALS. Потому что другой хэш-код гарантирует различное содержимое в объекте.

    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. 

хэш-карта работает по принципу хеширования

метод HashMap get(Key k) вызывает метод hashCode для ключевого объекта и применяет возвращенное hashValue к своей собственной статической хэш-функции, чтобы найти местоположение ведра(резервный массив), где ключи и значения хранятся в виде вложенного класса, называемого Entry (Map.Вступление. ) Таким образом, Вы пришли к выводу, что из предыдущей строки ключ и значение хранятся в ведре как форма объекта ввода . Поэтому думая, что только значение хранится в ведро не правильное и не произведет хорошего впечатления на интервьюера .

  • всякий раз, когда мы вызываем get( Key k ) метод на объекте HashMap . Сначала он проверяет, является ли ключ null или нет . Обратите внимание, что в HashMap может быть только один нулевой ключ .

Если ключ равен null, то нулевые ключи всегда сопоставляются с хэшем 0, таким образом, индекс 0.

Если key не равен null, он вызовет hashfunction на ключевом объекте, см. строку 4 в приведенном выше методе, т. е. ключ.hashCode (), поэтому после ключа.hashCode () возвращает hashValue , строка 4 выглядит как

            int hash = hash(hashValue)

и теперь он применяет возвращенное hashValue в свою собственную функцию хэширования .

мы можем задаться вопросом, почему мы снова вычисляем hashvalue, используя hash (hashValue). Ответ: он защищает от некачественных хэш-функций.

теперь final hashvalue используется для поиска местоположения ковша, в котором хранится объект записи . Объект запись в ведро такой магазинах (хэш,ключ,значение,bucketindex)


каждый объект записи представляет пару ключ-значение. Поле next относится к другому объекту записи, если в ведре более 1 записи.

иногда может случиться, что хэш-коды для 2 разных объектов одинаковы. В этом случае 2 объекта будут сохранены в одном ведре и будут представлены как LinkedList. Точка входа-это недавно добавленный объект. Этот объект относится к другому объекту со следующим полем и так один. Последняя запись относится к null. При создании HashMap по умолчанию конструктор

массив создается с размером 16 и балансом нагрузки по умолчанию 0.75.

enter image description here

(источник)


Я не буду вдаваться в детали того, как работает HashMap, но приведу пример, чтобы мы могли вспомнить, как работает HashMap, связывая его с реальностью.

У нас есть ключ, значение ,хэш-код и ведро.

на некоторое время мы свяжем каждый из них со следующим:

  • Ведро -> Общество
  • HashCode - > адрес Общества (уникальный всегда)
  • значение - > дом в обществе
  • Ключ -> Дом адрес.

Используя Карту.вам(ключ) :

Стиви хочет попасть в дом своего друга (Жосса), который живет на вилле в VIP-обществе, пусть это будет общество JavaLovers. Адрес жосса-его SSN (который отличается для всех). Существует индекс, в котором мы узнаем название Общества, основанное на SSN. Этот индекс можно рассматривать как алгоритм для поиска хэш-кода.

  • общество SSN Имя
  • 92313 (Жосса) -- JavaLovers
  • 13214 -- AngularJSLovers
  • 98080 -- JavaLovers
  • 53808 -- BiologyLovers

  1. этот SSN(ключ) сначала дает нам хэш-код (из таблицы индексов), который является не чем иным, как именем общества.
  2. теперь дома mulitple могут находиться в одном обществе, поэтому хэш-код может быть общим.
  3. предположим, что общество является общим для двух дома, как мы собираемся определить, в какой дом мы собираемся, да, используя ключ (SSN), который является не чем иным, как адресом дома

Используя Карту.поставить(ключ,значение)

Это находит подходящее общество для этого значения, находя хэш-код, а затем значение сохраняется.

Я надеюсь, что это поможет, и это открыто для модификаций.


в суммеризованной форме того, как hashMap работает на java?

HashMap работает по принципу хеширования, у нас есть метод put() и get() для хранения и извлечения объекта из HashMap. Когда мы передаем метод key и value to put () для хранения в HashMap, он использует метод key object hashcode () для вычисления хэш-кода, и они, применяя хэширование к этому хэш-коду, идентифицируют местоположение ведра для хранения объекта value. При извлечении используется метод Key object equals чтобы узнать правильную пару значений ключа и объект возвращаемого значения, связанный с этим ключом. HashMap использует связанный список в случае столкновения, и объект будет сохранен в следующем узле связанного списка. Также HashMap хранит оба кортежа ключ+значение в каждом узле связанного списка.


два объекта равны, означает, что они имеют одинаковый хэш-код, но не наоборот

обновление Java 8 в HashMap -

вы делаете эту операцию в ваш код -

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

Итак, предположим, что ваш хэш-код вернулся для обоих ключей "old" и "very-old" то же самое. То, что произойдет.

myHashMap является HashMap, и предположим, что изначально вы не указали его емкость. Таким образом, емкость по умолчанию согласно java 16 лет. Итак, как только вы инициализировали hashmap с помощью нового ключевого слова, он создал 16 ведер. теперь, когда вы выполнили первое утверждение -

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

затем хэш-код для "old" вычисляется, и потому, что хэш-код может быть очень большим целым числом, поэтому java внутренне сделала это - (хэш-это хэш-код здесь и > > > - правый сдвиг)

hash XOR hash >>> 16

таким образом, чтобы дать как больше pictureit вернет некоторый индекс, который будет от 0 до 15. Теперь ваша пара ключевых значений "old" и "key-value-pair" будет преобразован в переменную экземпляра ключа и значения объекта ввода. и тогда этот объект записи будет сохранен в ведре, или вы можете сказать, что при определенном индексе этот объект записи будет сохранен.

FYI-Entry-это класс в интерфейсе Карты-Map.Запись, с этой подписью / определением

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

теперь, когда вы выполните следующую инструкцию -

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

и "very-old" дает тот же хэш-код как "old", поэтому эта новая пара значений ключа снова отправлено в тот же индекс или в ту же корзину. Но так как это ведро не пустое, то next переменная объекта ввода используется для хранения этой новой пары значений ключа.

и это будет сохранено как связанный список для каждого объекта, который имеет тот же хэш-код, но TRIEFY_THRESHOLD указан со значением 6. поэтому после этого связанный список преобразуется в сбалансированное дерево (красно-черное дерево) с первым элементом в качестве корня.


как говорится, картина стоит 1000 слов. Я говорю: Какой код лучше, чем 1000 слов. Вот исходный код HashMap. Получить метод:

/**
     * 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;
    }

таким образом, становится ясно, что хэш используется для поиска "ведра", и первый элемент всегда проверяется в этом ведре. Если нет, то ... --2--> ключа используется для поиска фактического элемента в связанном списке.

посмотрим 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;
    }

это немного сложнее, но он будет ясно, что новый элемент помещается во вкладку в позиции, рассчитанной на основе хэша:

i = (n - 1) & hash здесь i - это индекс, в который будет помещен новый элемент (или это"ведро"). n - размер tab array (массив "ведер").

во-первых, его пытаются поставить в качестве первого элемента в этом "ведре". Если элемент уже существует,добавьте новый узел в список.


это будет длинный ответ, возьмите напиток и читайте дальше ...

хеширование - это сохранение пары ключ-значение в памяти, которая может быть прочитана и записана быстрее. он хранит ключи в массиве и значения в LinkedList .

допустим, я хочу сохранить 4 пары ключевых значений -

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

поэтому для хранения ключей нам нужен массив из 4 элементов . Теперь, как сопоставить один из этих 4 Ключей с 4 индексами массива (0,1,2,3)?

Итак, java находит хэш-код отдельных ключей и сопоставляет их с определенным индексом массива . Формулы хэш-кода -

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

гашиш и девушка !! Я знаю, о чем ты думаешь. Ваше увлечение этим диким дуэтом может заставить вас пропустить важную вещь .

почему java умножить его на 31 ?

это потому, что 31-нечетное простое в виде 2^5 – 1 . И нечетное простое уменьшает вероятность хэша Столкновение!--14-->

теперь, как этот хэш-код сопоставляется с индексом массива?

ответ:Hash Code % (Array length -1) . Так что “girl” отображается на (3173020 % 3) = 1 в нашем случае . который является вторым элементом массива .

и значение "ahhan" хранится в LinkedList, связанном с индексом массива 1 .

HashCollision - если вы попытаетесь найти hasHCode ключи “misused” и “horsemints” С помощью формулы описанные выше, вы увидите, что оба дают нам то же самое 1069518484. Whooaa !! урок усвоен -

2 равные объекты должны иметь одинаковый хэш-код, но нет никакой гарантии, если хэш-код соответствует, тогда объекты равны . Поэтому он должен хранить оба значения, соответствующие "неправильно" и "horsemints" ковш 1 (1069518484 % 3) .

теперь хэш-карта выглядит как –

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

теперь, если какое-то тело пытается найти значение ключа “horsemints” , java быстро найдет его хэш-код, модуль и начнет поиск его значения в соответствующем LinkedList index 1 . Таким образом, нам не нужно искать все 4 индекса массива, что делает доступ к данным быстрее.

но , подождите , одну секунду . в этом linkedList есть 3 значения, соответствующие индексу массива 1, как он узнает, какое из них было значением для ключа "horsemints"?

на самом деле я солгал, когда сказал, что HashMap просто хранит значения в LinkedList не .

он хранит обе пары ключевых значений как запись карты. На самом деле карта выглядит так .

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

теперь вы можете видеть, проходя через linkedList, соответствующий ArrayIndex1, он фактически сравнивает ключ каждой записи этого LinkedList с "horsemints", и когда он находит его, он просто возвращает его значение .

Надеюсь, вам было весело, читая его:)