Оскільки існує певна плутанина щодо того, який алгоритм використовує Java HashMap (у реалізації Sun / Oracle / OpenJDK), тут відповідні фрагменти вихідного коду (з OpenJDK, 1.6.0_20, на Ubuntu):
/**
* Returns the entry associated with the specified key in the
* HashMap. Returns null if the HashMap contains no mapping
* for the key.
*/
final Entry<K,V> getEntry(Object key) {
int hash = (key == null) ? 0 : 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 != null && key.equals(k))))
return e;
}
return null;
}
Цей метод (цитування з рядків 355 - 371) викликається при пошуку записів у таблиці, наприклад, від get()
, containsKey()
та деяких інших. Цикл for тут проходить через пов'язаний список, сформований об'єктами введення.
Ось код для об'єктів введення (рядки 691-705 + 759):
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
final int hash;
/**
* Creates new entry.
*/
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
// (methods left away, they are straight-forward implementations of Map.Entry)
}
Відразу після цього приходить addEntry()
метод:
/**
* Adds a new entry with the specified key, value and hash code to
* the specified bucket. It is the responsibility of this
* method to resize the table if appropriate.
*
* Subclass overrides this to alter the behavior of put method.
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
Це додає новий запис на передній частині відра із посиланням на старий перший запис (або нульовий, якщо такого немає). Аналогічно, removeEntryForKey()
метод проходить по списку і піклується про видалення лише одного запису, залишаючи решту списку недоторканим.
Отже, ось зв’язаний список входів для кожного сегмента, і я дуже сумніваюся, що це змінилося з _20
на _22
, оскільки так було з 1.2.
(Цей код є (c) 1997-2007 Sun Microsystems і доступний під GPL, але для копіювання краще використовувати оригінальний файл, що міститься у src.zip у кожному JDK від Sun / Oracle, а також у OpenJDK.)