面試高頻問題:HashMap實現原理

今天給同窗們講講一個面試常常遇到的高頻問題,HashMap實現原理,但願在金三銀四的季節對同窗們有幫助。面試

HashMap結構圖目錄
 1、嘮叨
 2、解析思路

 3、get方法
 4、put方法
 5、resize方法

 1、嘮叨


認真閱讀了下HashMap的實現方式,也參考了網上別人的一些解析,我的以爲仍是有些東西想說。網上有的文章名字爲HashMap源碼解析,實際上就是給它裏面的一些方法加上一些註釋而已,有很多都是這樣的。
我本身看源碼的時候,發現不是別人不想解析,而是它的實現真的須要親自研讀,多理順幾遍才知道怎麼回事。
我在這裏解析的文字描述也較多,無論誰的解析,本身也都要看一下JDK源碼的具體實現,咱們僅提供參考而已。數組

2、解析思路


源碼不太方便看,先說明一下個人閱讀思路。
1.把經常使用的幾個方法拷貝到文本編輯器裏面。
2.HashMap中不一樣的時候會有不一樣的流程,梳理方法中的邏輯流程。就像採用極端法,採用特殊的數據,而後查看方法執行語句。未執行的語句暫時不考慮。
3.註釋源碼...我以爲HashMap的實現方式不夠好,關鍵的幾個方法裏面包含的狀況太多了,閱讀起來是有難度的,而寫程序的目的之一不就是讓其餘開發者閱讀嗎?一個方法內部作了太多的事情,違反了代碼整潔的規則,一個函數作要儘可能少的事情。
解析
以前稍微介紹了一些HashMap的特性,HashMap初探。
(https://www.jianshu.com/p/be9ffb76db30)這裏接着深刻。編輯器

3、get方法

先挑最簡單的說函數

 

 

1 先從數組下標,找到對應的Node2. 
2 若是Node裏的第一個節點命中,直接返回
3 若是有衝突,則經過key.equals(k)去查找對應的entry
4 若爲樹,則在樹中經過key.equals(k)查找,O(logn);
5 若爲鏈表,則在鏈表中經過key.equals(k)查找,O(n)。put方法這個中間涉及的邏輯多一些,方法須要分不一樣的步驟看。spa

 


 

4、put方法


這個中間涉及的邏輯多一些,方法須要分不一樣的步驟看。
思路:
1對key的hashCode()作hash,而後再計算index;
2若是沒碰撞直接放到bucket裏;
3若是碰撞了,以鏈表的形式存在buckets後;
4若是節點已經存在就替換old 5value(保證key的惟一性)
6若是碰撞致使鏈表過長(大於等於TREEIFY_THRESHOLD),就把鏈表轉換成紅黑樹;
7若是Node的容量滿了(超過load factor*current capacity),就要resize。3d



 

通常不發生碰撞的時候,相對簡單,數據量較小的狀況下。blog

 

 

我解釋下關於碰撞衝的循環。
1.查看是否存在相同的key,存在相同的key跳出循環,覆蓋key的value。
2.若是不存在相同的key,在鏈表末尾插入新的Node若是鏈表節點過長,轉換爲樹。
3.若是鏈表節點過長,轉換爲樹。索引

 

 

紅黑樹的部分,咱們下次單獨解析ci

 5、resize方法


這個涉及的內容,有很多線須要捋一捋。首先看申明時候會resize()。它們都在調用put的時候執行的。開發

1.table == 的時候

 

 

2.鍵值映射的的數目大於臨界值的時候。

 

 

6、resize具體方法


 

 

若是是第一次resize,咱們抽出來會執行到的語句。
1.初始化容量
2.初始化threshold,也就是初始化臨界值,決定了table的鍵值對數目到何時會再次resize()


 

第二次及後續的resize執行流程

 


 

resize中對有碰撞的鏈表的操做寫的頗有意思,再敘述一下。在從新分配索引的時候,有從新組建鏈表的操做。

舉個比較誇張的例子,讀者就明白了。
1.e.hash < 2,那麼e.hash&oldCap就等於0,索引爲小於以前hash表大小之內的索引。也就是當初的索引不變。
2.e.hash > 2的時候,e.hash&old不等於0,那麼它的索引就爲當前表的索引再加上新擴容的大小。


                案例圖

這個圖說的是,當hashmap的表大小爲2擴充到4的時候,本來掛載在1位置的鏈表,從新分配以後的樣子。

最後 篇幅有限,我這裏僅僅介紹了get方法,put方法,resize方法的具體原理,文章就已經很是長了,不利於閱讀。 下次再補充一下HashMap的hash方法原理,其他的相關注意事項。

相關文章
相關標籤/搜索