HashMap源碼詳解

何為HashMap环础?

HashMap是用哈希表(直接一點(diǎn)可以說數(shù)組加單鏈表)+ 紅黑樹實(shí)現(xiàn)的map類(其實(shí)所謂Map其實(shí)就是保存了兩個(gè)對(duì)象之間的映射關(guān)系的一種集合)。

版本之更迭

–》JDK 1.7?: Table數(shù)組 (也有叫做 "位桶" )?+ Entry鏈表(頭插法)弱睦;

–》JDK 1.8?:?Table數(shù)組 (也有叫做 "位桶" )?+ Node鏈表(換了名) + 紅黑樹(尾插法);

HashMap的實(shí)現(xiàn)原理

當(dāng)系統(tǒng)開始初始化 HashMap 時(shí),系統(tǒng)會(huì)創(chuàng)建一個(gè)長度為 capacity(默認(rèn)為2的16次冪) 的 Entry 數(shù)組温赔。

Entry.jpg

這個(gè)數(shù)組被用來存儲(chǔ)key-value對(duì),每?個(gè)鍵值對(duì)組成了?個(gè)Entry實(shí)體鬼癣,存儲(chǔ)元素(也就是一個(gè) Entry實(shí)體)的位置被稱為 "桶 (bucket) "陶贼,每個(gè) bucket 都有其指定索引,系統(tǒng)可以根據(jù)其索引快速訪問該 bucket 里存儲(chǔ)的元素待秃。

Entry.jpg

無論何時(shí)拜秧,HashMap 的每個(gè) "桶" 只存儲(chǔ)一個(gè)元素,由于 Entry 對(duì)象可以包含一個(gè)引用變量(就是 Entry 構(gòu)造器的的最后一個(gè)參數(shù)Next指針)用于指向下一個(gè) Entry章郁,因此可能出現(xiàn)的情況是:HashMap 的 bucket 中只有一個(gè) Entry枉氮,但這個(gè) Entry 指向另一個(gè) Entry ——這就形成了一個(gè) Entry 鏈(單向的鏈表結(jié)構(gòu))。

數(shù)據(jù)結(jié)構(gòu).jpg

參數(shù)說明

參數(shù)說明.jpg

HashMap的初始化

HashMap有4個(gè)構(gòu)造器暖庄,其他構(gòu)造器如果用戶沒有傳入initialCapacity 和loadFactor這兩個(gè)參數(shù)嘲恍,會(huì)使用默認(rèn)值

初始化.jpg

從上面這段代碼我們可以看出,在常規(guī)構(gòu)造器中雄驹,沒有為數(shù)組table分配內(nèi)存空間(有一個(gè)入?yún)橹付∕ap的構(gòu)造器例外)佃牛,只是賦值,只有在執(zhí)行put操作的時(shí)候才真正構(gòu)建table數(shù)組医舆,為什么要這樣做俘侠?估計(jì)是避免初始化了HashMap之后不使用反而占用內(nèi)存吧

OK,接下來我們來看看put操作的實(shí)現(xiàn)

HashMap的存儲(chǔ)操作

put.image

inflateTable這個(gè)方法用于為主干數(shù)組table在內(nèi)存中分配存儲(chǔ)空間,通過roundUpToPowerOf2(toSize)可以確保capacity為大于或等于toSize的最接近toSize的二的次方數(shù)蔬将,比如toSize = 13,則capacity = 16; toSize = 16,capacity = 16; toSize =17,capacity = 32.

inflateTable.image

roundUpToPowerOf2中的這段處理使得數(shù)組長度一定為2的次冪爷速,Integer.highestOneBit是用來獲取一個(gè)小于等于i的2的冪次方數(shù)

roundUpToPowerOf2.jpg

number減1是為了所獲取的結(jié)果不超過原數(shù)

number.jpg

返回一個(gè)小于等于i的2的冪次方數(shù)

highestOneBit.jpg

按位從左向右移動(dòng),取i的最高位霞怀,其他位清0(右移與或運(yùn)算的目的就是想讓某個(gè)數(shù)字的低位都變?yōu)?惫东,再用該結(jié)果減去該結(jié)果右移一位后的結(jié)果,則相當(dāng)于清除了原數(shù)字的低位毙石,即得到了我們想要的結(jié)果)

運(yùn)算過程.jpg

hash函數(shù)

hash.jpg

以上hash函數(shù)計(jì)算出的值廉沮,通過indexFor進(jìn)一步處理來獲取實(shí)際的存儲(chǔ)位置

indexFor.jpg

h&(length-1)保證獲取的index一定在數(shù)組范圍內(nèi),舉個(gè)例子徐矩,默認(rèn)容量16滞时,length-1=15,h=18,轉(zhuǎn)換成二進(jìn)制計(jì)算為index=2滤灯。位運(yùn)算對(duì)計(jì)算機(jī)來說坪稽,性能更高一些(HashMap中有大量位運(yùn)算曼玩,計(jì)算機(jī)底層就是2進(jìn)制運(yùn)算)。數(shù)組下標(biāo)的獲取無視了HashCode高位的參與窒百,所以有了以上Hash函數(shù)代碼中對(duì)HashCode進(jìn)行進(jìn)一步的運(yùn)算和調(diào)整黍判,避免太多低位相同的HashCode存儲(chǔ)在同一位置上,鏈表過長篙梢,遍歷時(shí)間太久

運(yùn)算.jpg

再來看看addEntry的實(shí)現(xiàn):

addEntry.jpg

通過以上代碼能夠得知样悟,當(dāng)size大于閾值并且即將要發(fā)生哈希沖突(?jdk7中resize,只有當(dāng) size>=threshold并且 table中的那個(gè)槽中已經(jīng)有Entry時(shí)庭猩,才會(huì)發(fā)生resize。)的時(shí)候陈症,需要進(jìn)行數(shù)組擴(kuò)容蔼水,擴(kuò)容時(shí),需要新建一個(gè)長度為之前數(shù)組2倍的新的數(shù)組录肯,然后將當(dāng)前的Entry數(shù)組中的元素全部傳輸過去趴腋,擴(kuò)容后的新數(shù)組長度為之前的2倍,所以擴(kuò)容相對(duì)來說是個(gè)耗資源的操作论咏。

createEntry.jpg
new.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末优炬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子厅贪,更是在濱河造成了極大的恐慌蠢护,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件养涮,死亡現(xiàn)場(chǎng)離奇詭異葵硕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)贯吓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門懈凹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人悄谐,你說我怎么就攤上這事介评。” “怎么了爬舰?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵们陆,是天一觀的道長。 經(jīng)常有香客問我情屹,道長棒掠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任屁商,我火速辦了婚禮烟很,結(jié)果婚禮上颈墅,老公的妹妹穿的比我還像新娘。我一直安慰自己雾袱,他們只是感情好恤筛,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著芹橡,像睡著了一般毒坛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上林说,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天煎殷,我揣著相機(jī)與錄音,去河邊找鬼腿箩。 笑死豪直,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的珠移。 我是一名探鬼主播弓乙,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼钧惧!你這毒婦竟也來了暇韧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤浓瞪,失蹤者是張志新(化名)和其女友劉穎懈玻,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乾颁,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酪刀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钮孵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骂倘。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖巴席,靈堂內(nèi)的尸體忽然破棺而出历涝,到底是詐尸還是另有隱情,我是刑警寧澤漾唉,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布荧库,位于F島的核電站,受9級(jí)特大地震影響赵刑,放射性物質(zhì)發(fā)生泄漏分衫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一般此、第九天 我趴在偏房一處隱蔽的房頂上張望蚪战。 院中可真熱鬧牵现,春花似錦、人聲如沸邀桑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽壁畸。三九已至贼急,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捏萍,已是汗流浹背太抓。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留令杈,地道東北人走敌。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像这揣,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子影斑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • HashMap是最常用的數(shù)據(jù)結(jié)構(gòu)之一给赞,是JDK中util包下的一個(gè)集合類,基于Map接口實(shí)現(xiàn)矫户、允許null鍵/值片迅、...
    幾行代碼閱讀 1,576評(píng)論 0 3
  • 這篇文章打算詳細(xì)理一下HashMap的源碼,可能會(huì)比較長皆辽,基于JDK1.8 HashMap數(shù)據(jù)結(jié)構(gòu) HashMap...
    章小傳閱讀 286評(píng)論 0 0
  • HashMap 概述 HashMap 是基于哈希表的 Map 接口的非同步實(shí)現(xiàn)柑蛇。此實(shí)現(xiàn)提供所有可選的映射操作,并允...
    一只好奇的茂閱讀 501評(píng)論 0 19
  • 概述 HashMap是基于哈希表(散列表)驱闷,實(shí)現(xiàn)Map接口的雙列集合耻台,數(shù)據(jù)結(jié)構(gòu)是“鏈表散列”,也就是數(shù)組+鏈表 空另,...
    gogoingmonkey閱讀 30,147評(píng)論 5 14
  • 目的 深入講解HashMap源碼盆耽,如題,將從put(K key, V value)方法調(diào)用開始 put方法 當(dāng)傳入...
    IT那些事兒閱讀 121評(píng)論 0 0