聲明,本文用得是jdk1.8html
前面已經講了Collection的總覽和剖析List集合以及散列表、Map集合、紅黑樹的基礎了:java
本篇主要講解HashMap,以及涉及到一些與hashtable的比較~算法
看這篇文章以前最好是有點數據結構的基礎:數組
固然了,若是講得有錯的地方還請你們多多包涵並不吝在評論去指正~安全
首先看看HashMap的頂部註釋說了些什麼:微信
再來看看HashMap的類繼承圖:數據結構
下面咱們來看一下HashMap的屬性:post
成員屬性有這麼幾個:性能
再來看一下hashMap的一個內部類Node:測試
咱們知道Hash的底層是散列表,而在Java中散列表的實現是經過數組+鏈表的~
再來簡單看看put方法就能夠印證咱們的說法了:數組+鏈表-->散列表
咱們能夠簡單總結出HashMap:
HashMap的構造方法有4個:
在上面的構造方法最後一行,咱們會發現調用了tableSizeFor()
,咱們進去看看:
這是位運算算法,具體流程可參考:
看完上面可能會感到奇怪的是:爲啥是將2的整數冪的數賦給threshold?
capacity * load factor
纔對的。其實這裏僅僅是一個初始化,當建立哈希表的時候,它會從新賦值的:
至於別的構造方法都差很少,這裏我就不細講了:
put方法能夠說是HashMap的核心,咱們來看看:
咱們來看看它是怎麼計算哈希值的:
爲何要這樣幹呢??咱們通常來講直接將key做爲哈希值不就行了嗎,作異或運算是幹嗎用的??
咱們看下來:
咱們是根據key的哈希值來保存在散列表中的,咱們表默認的初始容量是16,要放到散列表中,就是0-15的位置上。也就是tab[i = (n - 1) & hash]
。能夠發現的是:在作&
運算的時候,僅僅是後4位有效~那若是咱們key的哈希值高位變化很大,低位變化很小。直接拿過去作&
運算,這就會致使計算出來的Hash值相同的不少。
而設計者將key的哈希值的高位也作了運算(與高16位作異或運算,使得在作&運算時,此時的低位其實是高位與低位的結合),這就增長了隨機性,減小了碰撞衝突的可能性!
下面咱們再來看看流程是怎麼樣的:
新值覆蓋舊值,返回舊值測試:
接下來咱們看看resize()
方法,在初始化的時候要調用這個方法,當散列表元素大於capacity * load factor
的時候也是調用resize()
接下來咱們看看getNode()
是怎麼實現的:
再來看看removeNode()
的實現:
從存儲結構和實現來說基本上都是相同的。它和HashMap的最大的不一樣是它是線程安全的,另外它不容許key和value爲null。Hashtable是個過期的集合類,不建議在新代碼中使用,不須要線程安全的場合能夠用HashMap替換,須要線程安全的場合能夠用ConcurrentHashMap替換
Hashtable具體閱讀源碼可參考:
在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,你們也能夠去交流交流。 謝謝支持了!但願能多介紹給其餘有須要的朋友
參考資料: