最近在用HashMap的時候,碰到一些問題,有疑惑,遂查看源代碼分析了一下。
我們知道,HashMap<K, V>是以鍵值對來讀寫數據的,那它底層用於存放Value的什麼?又如何判斷兩個Key是否相等呢?
首先說說哈希表的一些相關概念,可能有些名詞會有不同的叫法。
- 容量:散列表中散列數組大小
- 散列運算:key->散列值(散列數組下標)的算法, h ^= (h >>> 20) ^ (h >>> 12);return h ^ (h >>> 7) ^ (h >>> 4);
- 散列桶:散列值相同的元素的“線性集合”
- 加載因子(loadFactor):散列數組的加載率,一般小於75%比較理想(即元素數量/散列數組大小)。
-
- threshold = (int)(newCapacity * loadFactor);//閾值=新的容量*加載因子,當新增元素時達到了閾值就要再次擴容
- 散列查找:根據Key計算散列值,根據散列值(下標)找到在散列桶,在散列桶中順序比較Key,如果相同(Key的hascode相同、且equals()爲true)就返回Value;散列表中Value可以重複,只要其對應的Key不一樣即可;如果Key相同,新添加的元素會覆蓋原來的Value。
- Entry[] table;//Entry<K, V>型的數組,用於存放Value,每個Entry元素裏有Key, Value, hash與next(指向下一個Entry)
- int size;//所有Value的數量,Map的實際容量
- int threshold;//閥值,超過之後要對table擴容
- final float loadFactor;//加載因子
Entry | Entry | Entry | Entry | Entry |
final K key;
V value;
final int hash;
*/
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
if (key == null)//可以以null爲key
return putForNullKey(value);
int hash = hash(key.hashCode());//算出此key的hash code,用位移的算法
int i = indexFor(hash, table.length);//用hashcode&table長度,即將hashcode的高位清零,保留低位(與table長度一樣)的位,這樣得到的下標,一定在table的長度範圍之內。
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
//如果table下標爲i的位置爲null,則說明此散列桶爲空,直接將新元素添加到此即可
modCount++;
addEntry(hash, key, value, i);*注
return null;
}
Entry<K,V> e = table[bucketIndex];//e爲null
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);//新建Entry,next爲null
if (size++ >= threshold)//如果實際大小超過閥值,則擴容
resize(2 * table.length);
}