天天看點

JDK1.8源碼分析之HashMap(一) (轉)

一、前言

  在分析jdk1.8後的HashMap源碼時,發現網上好多分析都是基于之前的jdk,而Java8的HashMap對之前做了較大的優化,其中最重要的一個優化就是桶中的元素不再唯一按照連結清單組合,也可以使用紅黑樹進行存儲,總之,目标隻有一個,那就是在安全和功能性完備的情況下讓其速度更快,提升性能。好~下面就開始分析源碼。

二、HashMap資料結構

  

JDK1.8源碼分析之HashMap(一) (轉)

  說明:上圖很形象的展示了HashMap的資料結構(數組+連結清單+紅黑樹),桶中的結構可能是連結清單,也可能是紅黑樹,紅黑樹的引入是為了提高效率。是以可見,在分析源碼的時候我們不知不覺就溫習了資料結構的知識點,一舉兩得。

三、HashMap源碼分析

  3.1 類的繼承關系 

  可以看到HashMap繼承自父類(AbstractMap),實作了Map、Cloneable、Serializable接口。其中,Map接口定義了一組通用的操作;Cloneable接口則表示可以進行拷貝,在HashMap中,實作的是淺層次拷貝,即對拷貝對象的改變會影響被拷貝的對象;Serializable接口表示HashMap實作了序列化,即可以将HashMap對象儲存至本地,之後可以恢複狀态。

  3.2 類的屬性 

JDK1.8源碼分析之HashMap(一) (轉)
JDK1.8源碼分析之HashMap(一) (轉)

View Code

  說明:類的資料成員很重要,以上也解釋得很詳細了,其中有一個參數MIN_TREEIFY_CAPACITY,筆者暫時還不是太清楚,有讀者知道的話歡迎指導。

  3.3 類的構造函數

  1. HashMap(int, float)型構造函數

JDK1.8源碼分析之HashMap(一) (轉)
JDK1.8源碼分析之HashMap(一) (轉)

  說明:tableSizeFor(initialCapacity)傳回大于initialCapacity的最小的二次幂數值。

JDK1.8源碼分析之HashMap(一) (轉)
JDK1.8源碼分析之HashMap(一) (轉)

  說明:>>> 操作符表示無符号右移,高位取0。

  2. HashMap(int)型構造函數。

JDK1.8源碼分析之HashMap(一) (轉)
JDK1.8源碼分析之HashMap(一) (轉)

  3. HashMap()型構造函數。

JDK1.8源碼分析之HashMap(一) (轉)
JDK1.8源碼分析之HashMap(一) (轉)

  4. HashMap(Map<? extends K>)型構造函數。

JDK1.8源碼分析之HashMap(一) (轉)
JDK1.8源碼分析之HashMap(一) (轉)

  說明:putMapEntries(Map<? extends K, ? extends V> m, boolean evict)函數将m的所有元素存入本HashMap執行個體中。 

JDK1.8源碼分析之HashMap(一) (轉)
JDK1.8源碼分析之HashMap(一) (轉)

  3.4 重要函數分析

  1. putVal函數  

JDK1.8源碼分析之HashMap(一) (轉)
JDK1.8源碼分析之HashMap(一) (轉)

  說明:HashMap并沒有直接提供putVal接口給使用者調用,而是提供的put函數,而put函數就是通過putVal來插入元素的。

  2. getNode函數

JDK1.8源碼分析之HashMap(一) (轉)
JDK1.8源碼分析之HashMap(一) (轉)

  說明:HashMap并沒有直接提供getNode接口給使用者調用,而是提供的get函數,而get函數就是通過getNode來取得元素的。

  3. resize函數  

JDK1.8源碼分析之HashMap(一) (轉)
JDK1.8源碼分析之HashMap(一) (轉)

  說明:進行擴容,會伴随着一次重新hash配置設定,并且會周遊hash表中所有的元素,是非常耗時的。在編寫程式中,要盡量避免resize。

  在resize前和resize後的元素布局如下

JDK1.8源碼分析之HashMap(一) (轉)

  說明:上圖隻是針對了數組下标為2的桶中的各個元素在擴容後的配置設定布局,其他各個桶中的元素布局可以以此類推。

四、針對HashMap的思考

  4.1. 關于擴容的思考

  從putVal源代碼中我們可以知道,當插入一個元素的時候size就加1,若size大于threshold的時候,就會進行擴容。假設我們的capacity大小為32,loadFator為0.75,則threshold為24 = 32 * 0.75,此時,插入了25個元素,并且插入的這25個元素都在同一個桶中,桶中的資料結構為紅黑樹,則還有31個桶是空的,也會進行擴容處理,其實,此時,還有31個桶是空的,好像似乎不需要進行擴容處理,但是是需要擴容處理的,因為此時我們的capacity大小可能不适當。我們前面知道,擴容處理會周遊所有的元素,時間複雜度很高;前面我們還知道,經過一次擴容處理後,元素會更加均勻的分布在各個桶中,會提升通路效率。是以,說盡量避免進行擴容處理,也就意味着,周遊元素所帶來的壞處大于元素在桶中均勻分布所帶來的好處。如果有讀者有不同意見,也歡迎讨論~

五、總結

  至此,HashMap的源碼就分析到這裡了,其中了解了其中的核心函數和資料結構,那麼了解HashMap的源碼就不困難了。當然,此次分析中還有一些知識點沒有涉及到,如紅黑樹、序列化、拷貝等,以後有機會會進行詳細的說明和講解,謝謝各位園友的觀看~

http://www.cnblogs.com/leesf456/p/5242233.html