HashMap
HashMap基于哈希表的 Map 接口的實現(xiàn)。允許使用 null 值和 null 鍵。不保證映射的順序,特別是它不保證該順序恒久不變。HashMap不是線程安全的,可以通過Collections類的靜態(tài)方法synchronizedMap獲得線程安全的HashMap。
HashMap的底層主要是基于數(shù)組和鏈表來實現(xiàn)的。HashMap中主要是通過key的hashCode來計算hash值的,只要hashCode相同,計算出來的hash值就一樣。如果存儲的對象對多了,就有可能不同的對象所算出來的hash值是相同的,這就出現(xiàn)了所謂的hash沖突。解決hash沖突的方法有很多,HashMap底層是通過鏈表來解決hash沖突的。
圖中,紫色部分即代表哈希表,也稱為哈希數(shù)組,數(shù)組的每個元素都是一個單鏈表的頭節(jié)點,鏈表是用來解決沖突的,如果不同的key映射到了數(shù)組的同一位置處,就將其放入單鏈表中。
HashMap其實就是一個Entry數(shù)組,Entry對象中包含了鍵和值,其中next也是一個Entry對象,它就是用來處理hash沖突的,形成一個鏈表。
/** Entry是單向鏈表。
* 它是 “HashMap鏈?zhǔn)酱鎯Ψā睂?yīng)的鏈表。
*它實現(xiàn)了Map.Entry 接口,即實現(xiàn)getKey(), getValue(), setValue(V value), equals(Object o), hashCode()這些函數(shù)
**/
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
// 指向下一個節(jié)點
Entry<K,V> next;
final int hash;
// 構(gòu)造函數(shù)。
// 輸入?yún)?shù)包括"哈希值(h)", "鍵(k)", "值(v)", "下一節(jié)點(n)"
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
//......
}
HashMap類的關(guān)鍵屬性
1 transient Entry[] table;//存儲元素的實體數(shù)組 默認(rèn)初始長度為 16
2
3 transient int size;//存放元素的個數(shù)
4
5 int threshold; //臨界值 當(dāng)實際大小超過臨界值時,會進行擴容threshold = 加載因子*容量
6
7 final float loadFactor; //加載因子 默認(rèn)0.75
8
9 transient int modCount;//被修改的次數(shù)
注意:
1、HashMap中通過hash&(length-1)的方法來代替取模(Hashtable中)來實現(xiàn)哈希值對應(yīng)數(shù)組下標(biāo)的映射。
2、哈希表的容量一定要是2的整數(shù)次冪,保證散列的均勻。
3、當(dāng)哈希表的size>threshold時,則調(diào)用Resize方法,此方法新建一個2*size的數(shù)組,并將舊數(shù)組中的數(shù)據(jù)復(fù)制到新數(shù)組中,所以效率很低。