由於有一些混淆的算法Java的HashMap的是使用(在Sun /甲骨文/ 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;
}
在查找表中的一個條目時,例如從get()
,containsKey()
和其他一些條目中調用此方法(引用來自第355行至第371行)。這裏的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()
方法遍歷列表並負責僅刪除一個條目,讓列表的其餘部分保持不變。
因此,這裏是每個存儲桶的鏈接條目列表,我非常懷疑這從_20
更改爲_22
,因爲它從1.2開始就是這樣。 (代碼爲(c)1997-2007 Sun Microsystems,並且可以在GPL下使用,但是可以更好地使用原始文件,該文件包含在Sun/Oracle的每個JDK的src.zip中,以及OpenJDK中)。
這是真的採取了由Sun /甲骨文在JDK 1.6.0_22兩者`Hashtable`和`HashMap`。 – 2011-02-12 21:42:04
@Nikita:不確定Hashtable,我現在無法訪問源代碼,但我100%確定HashMap在我的調試器中看到過的每個版本中都使用鏈接而不是線性探測。 – 2011-02-12 21:45:34
@Michael那麼,我現在正在查看HashMap的`public V get(Object key)'的源碼(與上面的版本相同)。如果你確實在這些鏈表出現的地方找到了精確的版本,我很有興趣知道。 – 2011-02-12 21:51:52