hashMap怎麼解決hash衝突的

學Java的都知道hashMap的底層是「鏈表散列」的數據結構也也能夠說是hash表。在put的實話先根據key的hashcode從新計算hash值的,而咱們又知道hash是一種算法。因此哈希碼並非徹底惟一的。java

查看哈希碼百科:算法

http://kaigejava.com/article/detail/168

 

null

 

哈希表能夠說就是數組鏈表,底層仍是數組可是這個數組每一項就是一個鏈表數組

一:爲何說hashmap的put方法是根據key進行hashcode計算的呢?數據結構

查看源碼:app

 

null

 

 

在查看hash方法,以下:測試

 

null

 

查看putVal方法:this

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,spa

boolean evict) {code

Node [] tab; Node p; int n, i;get

if ((tab = table) == null || (n = tab.length) == 0)

n = (tab = resize()).length;

if ((p = tab[i = (n - 1) & hash]) == null)

tab[i] = newNode(hash, key, value, null);

else {

Node e; K k;

if (p.hash == hash &&

((k = p.key) == key || (key != null && key.equals(k))))

e = p;

else if (p instanceof TreeNode)

e = ((TreeNode )p).putTreeVal(this, tab, hash, key, value);

else {

for (int binCount = 0; ; ++binCount) {

if ((e = p.next) == null) {

p.next = newNode(hash, key, value, null);

if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st

treeifyBin(tab, hash);

break;

}

if (e.hash == hash &&

((k = e.key) == key || (key != null && key.equals(k))))

break;

p = e;

}

}

if (e != null) { // existing mapping for key

V oldValue = e.value;

if (!onlyIfAbsent || oldValue == null)

e.value = value;

afterNodeAccess(e);

return oldValue;

}

}

++modCount;

if (++size > threshold)

resize();

afterNodeInsertion(evict);

return null;

}

二:hashmap怎麼解決key的hash值衝突問題的?

 

null

 

上圖是源碼截圖,說明:

1:初始化map的大小。默認是16

示例代碼:HashMap map = new HashMap();

2:若是tab爲空,就newNode一個放到鏈表中

示例代碼:map.put("aa",1); 也就是圖-1測試代碼中的1

3:根據key算出的hash值若是存在,且key的值和map中已經存在的值equals了。因此就不處理。

以下圖:

null

 

測試代碼如圖-1測試代碼中的1和 2

4:若是p是TreeNode的子類進行putTreeValu

5:若是key的hash值和map中已經存在的key的hash相等且key不一樣的時候,若是數組該位置上沒有元素,就直接將該元素放到此數組中的該位置上。

如圖-1測試代碼 1和4中key的hesh值都爲3104

圖-1測試代碼

 

null

 

在來看下Node這個內部類:

 

null

 

三:在來看看怎麼get方法

 

null

 

null

 

說明:

1:若是鏈表中第一個值的hash值和須要獲取的key的hash值相等的話,就直接取出。

2:若是鏈表first.next !=null就循環查找鏈表中的key,知道查詢到key.equals(k) 取出對應的值。

查看源碼或許感受不懂,那麼畫圖來講明:

 

null

 

總結:

數據結構:哈希表能夠說就是數組鏈表,底層仍是數組可是這個數組每一項就是一個鏈表。

map的put方法:

1:new hashMap的時候初始化默認大小爲16

2:當map.put("aa",1)的時候判斷map沒有值,就把aa算的hash值放到0X004的位置

3:當再次執行map.put("aa",1)的是計算aa的hash值爲3104.此時在OX004的位置已經有數據了。進行判斷存在的key和新put的key是否相同。相同不處理,值覆蓋

4:執行map.put("aa",2)的時候key和已經存在的key相同就直接覆蓋value了

5:執行map.put(3104,"cc")的時候,key的hash值也爲3104.此時數組中OX004已經存在數據,判斷key是否相同。發現3104和aa不相同【注:此時就發生了hash衝突】,那麼就aa這個鏈表前面追加3104

6:執行map.put("bb","cc")。假設bb計算出的hash值是3105就存放在了OX005上。

其餘依次類推

 

map的get方法:

當執行map.get("bb")的時候先計算出bb的hash值爲3105在對應的位置(也就是0X005)取出第一個判斷值是否是bb若是是就直接取出value.

當執行map.get("aa")的時候先計算出aa的hash值爲3104,去對應的位置取出判斷值(3104)不等於(aa)且還有next。就循環取出進行比較。

http://kaigejava.com/article/detail/168

相關文章
相關標籤/搜索