Vì có một số nhầm lẫn về thuật toán HashMap của Java đang sử dụng (trong triển khai Sun / Oracle / OpenJDK), đây là các đoạn mã nguồn liên quan (từ OpenJDK, 1.6.0_20, trên 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;
}
Phương pháp này (trích dẫn là từ dòng 355-371) được gọi khi nhìn lên một mục trong bảng, ví dụ từ get()
, containsKey()
và một số người khác. Vòng lặp for ở đây đi qua danh sách liên kết được tạo bởi các đối tượng mục nhập.
Đây là mã cho các đối tượng nhập (dòng 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)
}
Ngay sau đây là addEntry()
phương pháp:
/**
* 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);
}
Thao tác này thêm Mục nhập mới ở phía trước nhóm, với liên kết đến Mục nhập cũ đầu tiên (hoặc null, nếu không có mục nào như vậy). Tương tự, removeEntryForKey()
phương pháp này đi qua danh sách và chỉ xóa một mục nhập, giữ nguyên phần còn lại của danh sách.
Vì vậy, đây là danh sách mục nhập được liên kết cho từng nhóm và tôi rất nghi ngờ rằng điều này đã thay đổi từ _20
thành _22
, vì nó giống như thế này từ 1.2 trở đi.
(Mã này là (c) 1997-2007 Sun Microsystems và có sẵn theo GPL, nhưng để sao chép tốt hơn, hãy sử dụng tệp gốc, có trong src.zip trong mỗi JDK từ Sun / Oracle và cả trong OpenJDK.)