Java의 HashMap이 사용하는 알고리즘 (Sun / Oracle / OpenJDK 구현에서)에 대해 약간의 혼동이 있으므로 여기에 관련 소스 코드 스 니펫 (Ubuntu의 OpenJDK, 1.6.0_20)이 있습니다.
/**
* 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);
}
이렇게하면 이전 첫 번째 항목에 대한 링크와 함께 버킷의 전면에 새 항목이 추가됩니다 (또는 해당 항목이없는 경우 null). 마찬가지로removeEntryForKey()
메서드는 목록을 살펴보고 하나의 항목 만 삭제하고 나머지 목록은 그대로 둡니다.
따라서 여기에 각 버킷에 대한 링크 된 항목 목록 이 있으며 1.2에서 이와 같았 기 때문에 에서 _20
로 변경된 것은 의심 스럽 _22
습니다.
(이 코드는 (c) 1997-2007 Sun Microsystems이며 GPL에서 사용할 수 있지만 복사하려면 Sun / Oracle의 각 JDK 및 OpenJDK의 src.zip에 포함 된 원본 파일을 더 잘 사용하십시오.)