HashMap的初始容量機制及擴容機制

  通常在我們的應用中,HashMap是用到最多的數據結構之一,在JDK1.8之前,它的底層結構是數組+鏈表,而在JDK1.8之後,爲了查詢效率的優化(主要是當哈希碰撞較多的時候),它的底層結構變成了數組+鏈表+紅黑樹。今天就來探討一下HashMap的擴容機制,這也是面試時被問到最多的問題。首先看一下源碼中HashMap的四種構造方法。

  從源碼中可以看出:HashMap提供四種構造方法:一是給定初始容量和加載因子的構造方法,二是給定初始容量,使用默認的加載因子,三是什麼參數都不給,使用默認的初始容量和默認的加載因子,四是傳進一個Map,使用默認的加載因子。從上面的構造方法可以看出,無論是使用默認的初始容量,還是使用默認的初始容量,當你調用HashMap的構造方法時,HashMap是沒有進行初始化容量,也就是現在是一個空的HashMap(容量爲0),這是因爲HashMap使用的懶加載機制,只有你第一次向HashMap中添加元素時,才進行第一次的容量設置,查看put(K,V)的源碼:

從上圖中可以看出,put(K key, V value)調用了putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict)的方法,在putVal的方法中,當第一次向HashMap中添加對象時,會進行一個判空的處理,這時就調用resize()方法對HashMap進行容量設置,此時會有兩種情況的根據容量初始化。

第一種情況:當我們沒有設置初始化容量時,HashMap就使用默認的初始化容量,也就是16.

第二種情況:當我們設置了初始化容量,HashMap就會按照我們設置的容量進行設置嗎?答案是不一定。當你設置的初始化容量是2的n次方時,就會按照你設置的容量設置;當你設置的初始化容量不是2的n次方時,就會按照大於你設置的那個值但是最接近你設置的那個值的2的n次方進行設置。聽起來比較拗口,下面從源碼和實例進行說明。

  從HashMap的第一個構造方法我們可以看出,當我們給定初始容量時,會調用tableSizeFor(initialCapacity)方法進行容量設置,

這一系列的無符號右移操作和按位或運算返回的什麼結果,我們可以通過一個測試來說明。測試類如下:

運算結果如下:

結合源碼和實例,就可以體會到HashMap給定了初始容量時,它本身處理這個值得機制了。

還有就是HashMap什麼時候進行擴容呢?我們回到put()方法的源碼中,發現有下面一段代碼:

其中size是HashMap中添加鍵值對的數量,而threshold是容量*加載因子(capacity * load factor)得出的值,也是就當我們的容量是16,加載因子是0.75時,當鍵值對的數量大於16*0.75=12時,HashMap會進行擴容操作,回到resize()方法中,看它是怎麼擴容的?

可以看出,在容量不大於最大值的情況下,HashMap是以2倍的容量進行擴容的。那麼問題又來了,HashMap爲什麼會是2倍的形式進行擴容呢?下次再來分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章