Как Java реализует хеш-таблицы?
Кто-нибудь знает, как Java реализует свои хеш-таблицы (HashSet или HashMap)? Учитывая различные типы объектов, которые можно захотеть помещать в хеш-таблицу, представляется очень сложным создать хеш-функцию, которая будет хорошо работать для всех случаев.
Ответы
Ответ 1
HashMap и HashSet очень похожи. Фактически, второй содержит экземпляр первого.
A HashMap содержит массив ведер, чтобы содержать его записи. Размер массива всегда равен 2. Если вы не укажете другое значение, изначально есть 16.
Когда вы помещаете в него запись (ключ и значение), она решает ведро, в которое будет вставлена запись, вычисляя его из своего хэш-кода ключа (hashcode не является адресом своей памяти, а хэш не является модуль упругости). Различные записи могут сталкиваться в одном ведре, поэтому они будут помещены в список.
Записи будут вставлены до тех пор, пока они не достигнут коэффициента нагрузки. Этот коэффициент 0,75 по умолчанию и не рекомендуется изменять его, если вы не очень уверены в том, что делаете. 0,75 в качестве коэффициента загрузки означает, что HashMap из кодов 16 может содержать только записи 12 (16 * 0,75). Затем будет создан массив ведер, удвоив размер предыдущего. Все записи будут помещены снова в новый массив. Этот процесс известен как rehashing и может быть дорогостоящим.
Следовательно, наилучшая практика, если вы знаете, сколько записей будет вставлена, заключается в том, чтобы построить HashMap с указанием его конечного размера:
new HashMap(finalSize);
Ответ 2
Вы можете проверить источник HashMap
, например.
Ответ 3
Java зависит от реализации каждого класса метода hashCode() для равномерного распределения объектов. Очевидно, что плохой метод hashCode() приведет к проблемам с производительностью для больших хеш-таблиц. Если класс не предоставляет метод hashCode(), по умолчанию в текущей реализации будет возвращена некоторая функция (т.е. Хеш) адреса объекта в памяти. Цитата из документа API:
Насколько это разумно практично, метод hashCode, определенный классом Объект возвращает разные целые числа для отдельных объектов. (Это обычно реализуется путем преобразования внутренний адрес объекта в целое число, но это техника реализации не требуемый программным обеспечением JavaTM язык).
Ответ 4
Существует два общих способа реализации HashMap. Разница заключается в том, как один имеет дело с столкновениями.
Первый метод, который является одним из пользователей Java, делает каждое ведро в HashMap содержащим односвязный список. Для этого каждый ведро содержит тип Entry, который кэширует хэш-код, имеет указатель на ключ, указатель на значение и указатель на следующую запись. Когда в Java возникает столкновение, в список добавляется еще одна запись.
Другой метод обработки столкновений - просто поместить элемент в следующее пустое ведро. Преимущество этого метода заключается в том, что ему требуется меньше места, однако он усложняет удаление, как если бы ведро, следующее за удаленным элементом, не было пустым, нужно проверить, находится ли этот элемент в правильном или неправильном ведре и сдвинуть элемент если он изначально столкнулся с удаляемым элементом.
Ответ 5
Своими словами:
Объект Entry
создается для хранения ссылки на ключ и значение.
В HashMap имеется массив Entry
.
Индекс для данной записи - это хеш, возвращаемый key.hashCode()
Если есть столкновение (два ключа дали один и тот же индекс), запись сохраняется в атрибуте .next
существующей записи.
То, как два объекта с одним и тем же хэшем могут быть сохранены в коллекции.
Из этого ответа мы получаем:
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;
}
Сообщите мне, если у меня что-то не так.