HashMap就是這麼簡單【源碼剖析】

前言

聲明,本文用得是jdk1.8html

前面已經講了Collection的總覽和剖析List集合以及散列表、Map集合、紅黑樹的基礎了:java

本篇主要講解HashMap,以及涉及到一些與hashtable的比較~算法

看這篇文章以前最好是有點數據結構的基礎:數組

固然了,若是講得有錯的地方還請你們多多包涵並不吝在評論去指正~安全

1、HashMap剖析

首先看看HashMap的頂部註釋說了些什麼:微信

再來看看HashMap的類繼承圖:數據結構

下面咱們來看一下HashMap的屬性:post

成員屬性有這麼幾個:性能

再來看一下hashMap的一個內部類Node:測試

咱們知道Hash的底層是散列表,而在Java中散列表的實現是經過數組+鏈表的~

再來簡單看看put方法就能夠印證咱們的說法了:數組+鏈表-->散列表

咱們能夠簡單總結出HashMap:

  • 無序,容許爲null,非同步
  • 底層由散列表(哈希表)實現
  • 初始容量和裝載因子對HashMap影響挺大的,設置小了很差,設置大了也很差

1.1HashMap構造方法

HashMap的構造方法有4個:

在上面的構造方法最後一行,咱們會發現調用了tableSizeFor(),咱們進去看看:

這是位運算算法,具體流程可參考:

看完上面可能會感到奇怪的是:爲啥是將2的整數冪的數賦給threshold

  • threshold這個成員變量是閾值,決定了是否要將散列表再散列。它的值應該是:capacity * load factor纔對的。

其實這裏僅僅是一個初始化,當建立哈希表的時候,它會從新賦值的:

至於別的構造方法都差很少,這裏我就不細講了:

1.2put方法

put方法能夠說是HashMap的核心,咱們來看看:

咱們來看看它是怎麼計算哈希值的:

爲何要這樣幹呢??咱們通常來講直接將key做爲哈希值不就行了嗎,作異或運算是幹嗎用的??

咱們看下來:

咱們是根據key的哈希值來保存在散列表中的,咱們表默認的初始容量是16,要放到散列表中,就是0-15的位置上。也就是tab[i = (n - 1) & hash]。能夠發現的是:在作&運算的時候,僅僅是後4位有效~那若是咱們key的哈希值高位變化很大,低位變化很小。直接拿過去作&運算,這就會致使計算出來的Hash值相同的不少。

而設計者將key的哈希值的高位也作了運算(與高16位作異或運算,使得在作&運算時,此時的低位其實是高位與低位的結合),這就增長了隨機性,減小了碰撞衝突的可能性!

下面咱們再來看看流程是怎麼樣的:

新值覆蓋舊值,返回舊值測試:

接下來咱們看看resize()方法,在初始化的時候要調用這個方法,當散列表元素大於capacity * load factor的時候也是調用resize()

1.3get方法

接下來咱們看看getNode()是怎麼實現的:

1.4remove方法

再來看看removeNode()的實現:

2、HashMap與Hashtable對比

從存儲結構和實現來說基本上都是相同的。它和HashMap的最大的不一樣是它是線程安全的,另外它不容許key和value爲null。Hashtable是個過期的集合類,不建議在新代碼中使用,不須要線程安全的場合能夠用HashMap替換,須要線程安全的場合能夠用ConcurrentHashMap替換

Hashtable具體閱讀源碼可參考:

4、總結

在JDK8中HashMap的底層是:數組+鏈表(散列表)+紅黑樹

在散列表中有裝載因子這麼一個屬性,當裝載因子*初始容量小於散列表元素時,該散列表會再散列,擴容2倍!

裝載因子的默認值是0.75,不管是初始大了仍是初始小了對咱們HashMap的性能都很差

  • 裝載因子初始值大了,能夠減小散列表再散列(擴容的次數),但同時會致使散列衝突的可能性變大(散列衝突也是耗性能的一個操做,要得操做鏈表(紅黑樹)
  • 裝載因子初始值小了,能夠減少散列衝突的可能性,但同時擴容的次數可能就會變多!

初始容量的默認值是16,它也同樣,不管初始大了仍是小了,對咱們的HashMap都是有影響的:

  • 初始容量過大,那麼遍歷時咱們的速度就會受影響~
  • 初始容量太小,散列表再散列(擴容的次數)可能就變得多,擴容也是一件很是耗費性能的一件事~

從源碼上咱們能夠發現:HashMap並非直接拿key的哈希值來用的,它會將key的哈希值的高16位進行異或操做,使得咱們將元素放入哈希表的時候增長了必定的隨機性

還要值得注意的是:並非桶子上有8位元素的時候它就能變成紅黑樹,它得同時知足咱們的散列表容量大於64才行的~


明天要是無心外的話,可能會寫TreeMap,敬請期待哦~~~~

文章的目錄導航zhongfucheng.bitcron.com/post/shou-j…

若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y。爲了你們方便,剛新建了一下qq羣:742919422,你們也能夠去交流交流。 謝謝支持了!但願能多介紹給其餘有須要的朋友

參考資料:

相關文章
相關標籤/搜索