1. 程式人生 > >hashMap怎麽保證hash一致性的

hashMap怎麽保證hash一致性的

nod line == images set 並不是 abs top container

學Java的都知道hashMap的底層是“鏈表散列”的數據結構也也可以說是hash表。在put的實話先根據key的hashcode重新計算hash值的,而我們又知道hash是一種算法。所以哈希碼並不是完全唯一的。

查看哈希碼百科:


技術分享圖片


哈希表可以說就是數組鏈表,底層還是數組但是這個數組每一項就是一個鏈表

一:為什麽說hashmap的put方法是根據key進行hashcode計算的呢?

查看源碼:


技術分享圖片



在查看hash方法,如下:


技術分享圖片


查看putVal方法:

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

boolean evict) {

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

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值沖突問題的?


技術分享圖片


上圖是源碼截圖,說明:

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

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

2:如果tab為空,就newNode一個放到鏈表中

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

3:根據key算出的hash值如果存在,且key的值和map中已經存在的值equals了。所以就不處理。

如下圖:

技術分享圖片


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

4:如果p是TreeNode的子類進行putTreeValu

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

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

圖-1測試代碼


技術分享圖片


在來看下Node這個內部類:


技術分享圖片


三:在來看看怎麽get方法


技術分享圖片


技術分享圖片


說明:

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

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

查看源碼或許感覺不懂,那麽畫圖來說明:


技術分享圖片


總結:

數據結構:哈希表可以說就是數組鏈表,底層還是數組但是這個數組每一項就是一個鏈表。

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。就循環取出進行比較。


hashMap怎麽保證hash一致性的