Java基礎之HashMap閱讀總結

2021-08-04 16:18:56 字數 3037 閱讀 1283

工作中常常會遇到常用的類,但是由於封裝的太好,一般也不會出現太多的問題,就導致對底層的實現了解的比較少,最近想把這些東西全部都梳理一下,也順便多學習一些實現思路。歡迎共同**

帶著幾個問題去讀原始碼:

1. hashmap是基於哪種資料結構實現的?

2. hashmap是如何儲存的?

3. hashmap是如何取值的?

邊讀**邊理解:

其實只要閱讀他的put方法就能夠知道前兩個問題的答案!

public v put(k key, v value) 

// 具體的實現方法

final v putval(int hash, k key, v value, boolean onlyifabsent,

boolean evict)

//如果找到了指定資料,則結束

if (e.hash == hash &&

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

break;

// 如果沒有找到,則將e賦值給b繼續查詢他的下一級節點

p = e;}}

// e 物件如果不為空的話

// 將老值取出來

v oldvalue = e.value;

// 將新值替換進去

if (!onlyifabsent || oldvalue == null)

e.value = value;

afternodeaccess(e);

// 然後返回老值

return oldvalue;}}

//總是大小 + 1

++modcount;

// 如果大小超過設定的大小則進行重新調整

if (++size > threshold)

resize();

// 這個方法應該是交給你拓展的後置方法處理

afternodeinsertion(evict);

return

null;

}

resize()方法 - 乙個調整hashmap大小的方法,這個方法很關鍵,為後面的優化做了一些策略

final node resize() 

// 如果小於1e並且值又大於預設的閥值大小時

else

if ((newcap = oldcap << 1) < maximum_capacity &&

oldcap >= default_initial_capacity)

// **將當前大小調整為兩倍大小**

newthr = oldthr << 1; // double threshold

}else

if (oldthr > 0) // initial capacity was placed in threshold

newcap = oldthr;

else

// 計算新的resize上限

if (newthr == 0)

//調整閥值大小

threshold = newthr;

@suppresswarnings()

// 重新構建乙個新的陣列鍊錶,並將大小調整至閥值的大小

node newtab = (node)new node[newcap];

table = newtab;

// 老的hashmap不為空的情況下

if (oldtab != null)

// 這裡用來處理非原索引的邏輯,和上面差不多

else

} // 迴圈遍歷鍊錶的下一級節點!!!!

while ((e = next) != null);

// 原索引還是存放到原來的位置

if (lotail != null)

// 非原索引則根據當作陣列位置+老的極限值大小的位置,相加,得到儲存的位置

if (hitail != null) }}

}}

return newtab;

}

梳理一下上面所了解到的知識:
1. hashmap是由陣列+鍊錶+紅黑樹組成

2. hashmap的初始化陣列大小是16,儲存閥值大小當前陣列大小的75%,當陣列中的實際大小大於這個閥值是開始重新調整陣列大小,調整方案是以2倍遞增,當大小進行到integer.max_value,將不在擴容。

3. 擴容的方式是重新構建乙個新的鍊錶陣列,將老的陣列進行重組放入新的陣列鍊錶中

4. hashmap優化點:

1. 當鍊表長度超過8時,則將改造成treemap,也就是常說的紅黑樹,這樣做的目的就是為了防止某乙個鍊錶非常長,查詢速度很慢.

2. 擴容時會將鍊錶進行遍歷重組,重組的規則是判斷它的最後乙個bit是0還是1,因為我們使用的是2次冪的擴充套件(指長度擴為原來2倍),所以元素的位置要麼是在原位置,要麼是在原位置再移動2次冪的位置,所以打個比方,當前key處於陣列大小16的索引15位置,經過擴容之後的位置為15+16=31的位置。

3. 定位陣列的位置一共採用了三步:取key的hashcode、高位運算、取模運算

方法一:

static

final

int hash(object key)

方法二:

static

int indexfor(int h, int length)

你如果了解了上面如何定位陣列位置的話,應該就能夠有大概的思路,還是上遍**吧.

// 第乙個值是key的hash值

final nodegetnode(int hash, object key) while ((e = e.next) != null);}}

return

null;

}

參考資料: -寫的真他媽不是一般的好

java基礎之HashMap相關知識點

1.hashmap是一種由陣列和鍊錶構成的資料結構,用於儲存 key value對 元素,同時繼承了陣列的查詢優點和鍊錶的修改優點。2.hashmap是非同步的,所以速度很快。並且鍵和值可以為null。3.hashmap使用put key,value 方法儲存物件到hashmap中,使用get ke...

java 集合學習之hashMap

1 hashmap類繼承關係 public class hashmapextends abstractmap implements map,cloneable,serializable 存放示意圖 由此可以看出hash值一樣的節點會被存放在同一條鍊錶上,比原始遍歷equals查詢效率高 hash值相...

java之HashMap和HashSet的遍歷方法

今天去面試,面試官問到這個問題,發現自己用了這麼久的hashmap和hashset,竟然只勉強想到了一種方法,總結一下 hashmap遍歷方法 1 使用entryset for map.entryentry map.entryset 2 使用entry的迭代器 iterator iterator m...