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

В моем понимании я думаю:

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

Правильно ли я?

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

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

Ответ 1

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

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

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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.

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

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

HashMap hashMap = new HashMap();

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

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

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

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

Удаление

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

Ответ 4

Вы можете найти отличную информацию на http://javarevisited.blogspot.com/2011/02/how-hashmap-works-in-java.html

Подводя итог:

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

put (ключ, значение): HashMap сохраняет как ключ, так и объект значения как Map.Entry. Hashmap применяет hashcode (ключ) для получения ведра. если есть столкновение, HashMap использует LinkedList для хранения объекта.

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

Ответ 5

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


Внутренние классы

  • Map.Entry
    Представить единый объект на карте, объект key/value,
  • HashMap.Node
    Версия связанного списка node,

    Он может представлять:

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

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

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

Поля в HashMap

  • Node[] table
    Таблица ведра, (глава связанных списков).
    Если ведро не содержит элементов, то оно равно нулю, поэтому требуется только пробел ссылки,
  • 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;
}

мощность

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

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


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

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

Операция

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

    Затем попробуйте найти значение:
    • Если найдено, замените значение.
    • В противном случае добавьте новый node в начало связанного списка или вставьте в отсортированное дерево.
  • Изменение размера
    Когда threshold достигнут, удваивает емкость хэш-таблицы (table.lenght), а затем выполняет повторный хэш на всех элементах, чтобы перестроить таблицу. Это может быть дорогостоящей операцией.

Ответ 6

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

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

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

Ответ 7

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

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

Ответ 8

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


Мы знаем

  • HashMap хранит пару ключ-значение в Map.Entry(все мы знаем)

  • 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: здесь мы видим, как хеш-значение используется вместе с равными после того, как мы найдем ведро.

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

}

enter image description here

Ответ 9

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 имеют различный контент, то мы уверены, что наш переопределенный метод Hashcode будет генерировать разные Hashcode (116232,11601) для обоих объектов. СЕЙЧАС, поскольку существуют разные хеш-коды, поэтому он даже не захочет вызвать метод EQUALS. Поскольку другой объект Hashcode GUARANTEES DIFFERENT в объекте.

    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. 

Ответ 10

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

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

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

Если ключ равен NULL, тогда ключи Null всегда отображают хэш 0, таким образом, индекс 0.

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

            int hash = hash(hashValue)

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

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

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

Ответ 11

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

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

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

enter image description here

(Источник)

Ответ 12

В летней форме How hashMap работает в java?

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

Ответ 13

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

У нас есть Key, Value, HashCode и bucket.

В какой-то момент мы будем относить каждое из них следующим образом:

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

Использование Map.get(ключ):

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

  • Название общества SSN
  • 92313 (Josse's) - JavaLovers
  • 13214 - AngularJSLovers
  • 98080 - JavaLovers
  • 53808 - BiologyLovers

  • Этот SSN (ключ) сначала дает нам HashCode (из индексной таблицы), который является ничем иным, как именем Общества.
  • Теперь, mulitple дома могут находиться в одном обществе, поэтому HashCode может быть общим.
  • Предположим, что общество является общим для двух домов, как мы будем определять, к какому дому мы идем, да, используя ключ (SSN), который является ничем иным, как адресом дома.

Использование Map.put(ключ, значение)

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

Я надеюсь, что это поможет, и это доступно для изменений.

Ответ 14

два объекта равны, подразумевается, что они имеют один и тот же хэш-код, но не наоборот

Обновление 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");

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

hash XOR hash >>> 16

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

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

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

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

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

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

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

Ответ 15

Как сказано, картина стоит 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;
    }

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

Посмотрите способ 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 (массив "ведра" ).

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

Ответ 16

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

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

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

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

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

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

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. И нечетное число сокращает вероятность Hash Collision

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

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

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

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

2 равных объекта должны иметь один и тот же хэш-код, но нет гарантии, если hashCode соответствует, тогда объекты равны. Поэтому он должен хранить оба значения, соответствующие "неправильно используемым" и "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 массивные индексы, тем самым ускоряя доступ к данным.

Но, подождите, одна секунда. есть 3 значения в этом связанномList, соответствующем индексу 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 – 

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

Надеюсь, вам понравилось во время чтения:)