Java中的HashMap

自己在簡(jiǎn)書上看了不少的別人總結(jié),那么在借鑒前人(miaoLoveCode)基礎(chǔ)上自己再總結(jié)一番蒲拉。

HashMap1.8實(shí)現(xiàn)分析

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

1.8的HashMap數(shù)據(jù)結(jié)構(gòu)是由數(shù)組+(鏈表或紅黑樹)實(shí)現(xiàn)罕拂。

構(gòu)造方法

JDK8的構(gòu)造方法

幾個(gè)基本量:

  • capacity:容量,bucket數(shù)組長(zhǎng)度全陨,默認(rèn)長(zhǎng)度為16爆班;
  • loadFactor:裝載因子,默認(rèn)值為0.75辱姨,它決定了bucket填充程度柿菩;
  • threshold:決定了HashMap能夠放進(jìn)去的數(shù)據(jù)量。
    對(duì)于threshold的初始化會(huì)調(diào)用tableSizeFor方法計(jì)算出一個(gè)比initialCapacity大的第一個(gè)2的n次冪的值存入threshold雨涛。
tableSizeFor

bucket的初始化一般都是在第一次調(diào)用put方法時(shí)完成的枢舶。

Hash

JDK 8 中在進(jìn)行g(shù)et和put操作時(shí),會(huì)先根據(jù)key的hashCode進(jìn)行再散列替久,再進(jìn)行bucket對(duì)應(yīng)節(jié)點(diǎn)位置計(jì)算凉泄,請(qǐng)看以下示例:

hash及下標(biāo)計(jì)算

可以看出:h >>> 16,高16位補(bǔ)0蚯根,由于任意數(shù)跟0異或不變后众,所以hash的作用就是高16位不變,低16位和高16位做異或運(yùn)算颅拦,來(lái)達(dá)到減少碰撞的目的蒂誉。
hash方法的實(shí)現(xiàn):

hash方法

為了提高碰撞下的性能,當(dāng)鏈表節(jié)點(diǎn)等于8時(shí)距帅,JDK8用紅黑樹代替鏈表右锨,將原有鏈表部分查詢的時(shí)間復(fù)雜度o(n)提升為o(logn),繼續(xù)看JDK 8中的put方法的具體實(shí)現(xiàn)碌秸。

  • put方法
put實(shí)現(xiàn)
  • putVal
putVal實(shí)現(xiàn)

具體流程如下:
1.如果當(dāng)前bucket為空時(shí)绍移,調(diào)用resize()方法初始化悄窃;
2.根據(jù)key的hash值計(jì)算出所在的bucket節(jié)點(diǎn)的位置;
3.如果沒(méi)有沖突蹂窖,也就是

p = tab[i = (n - 1) & hash]=null

調(diào)用newNode方法封裝key-value鍵值對(duì)轧抗,并將其掛到 bucket對(duì)應(yīng)位置下,否則恼策,跳轉(zhuǎn)到步驟4鸦致;
4.如果發(fā)生沖突

  • 遍歷鏈表,如果該key已經(jīng)存在涣楷,則更新原有的oldValue為新的value分唾,并返回oldValue。直到鏈表末尾沒(méi)有相同的key的hash值和key(equals狮斗,==)力奋,則在末尾插入新節(jié)點(diǎn)胁后;
  • 如果key所在的節(jié)點(diǎn)為treeNode,調(diào)用rbtree(紅黑樹)的putTreeVal方法將改節(jié)點(diǎn)掛到rbtree上;
  • 如果插入節(jié)點(diǎn)后萍启,當(dāng)前bucket節(jié)點(diǎn)下鏈表長(zhǎng)度超過(guò)8秋柄,需要將原有的數(shù)據(jù)結(jié)構(gòu)鏈表變?yōu)閞btree益涧;

5.數(shù)據(jù)put完成之后锹杈,如果當(dāng)前數(shù)組長(zhǎng)度 > threshold,調(diào)用resize方法擴(kuò)容摔寨。

resize()

resize前半部分

resize的前半部分主要完成了新的capacity和threshold的計(jì)算去枷。從代碼實(shí)現(xiàn)可以看出,每一次擴(kuò)容是复,newCapacity和newThreshold均是擴(kuò)容前值的兩倍删顶,如此設(shè)計(jì)師為什么?先看個(gè)例子來(lái)說(shuō)明這樣子設(shè)計(jì)的原因:

resize后index計(jì)算

從小例子可以看出淑廊,resize后逗余,key所在bucket的節(jié)點(diǎn)位置保持不變。首先季惩,table.length也就是capacity肯定是2的n次方录粱,根據(jù)所在bucket節(jié)點(diǎn)下標(biāo)計(jì)算公式:index = hash & (table.length - 1),其實(shí)在進(jìn)行&運(yùn)算的時(shí)候蜀备,只是多了一個(gè)最高位1关摇,那么新位置要么保持原位置不變,要么在原位置 + oldCapacity碾阁,這個(gè)設(shè)計(jì)的巧妙就在于節(jié)省了一部分重新計(jì)算hash的時(shí)間,而且hash值高位出現(xiàn)0和1的概率均等些楣,在resize的過(guò)程又將節(jié)點(diǎn)平均分配到兩個(gè)bucket節(jié)點(diǎn)脂凶。

resize的后半部分對(duì)數(shù)據(jù)做了transfer宪睹,具體實(shí)現(xiàn)如下:

resize后半部分

總結(jié)

HashMap在JDk1.8比JDK1.7的優(yōu)化主要在:
1.引入rbtree,在bucket節(jié)點(diǎn)下鏈表長(zhǎng)度 = 8時(shí)將鏈表變成rbtree蚕钦;
2.優(yōu)化hash和resize亭病,減少resize帶來(lái)的hash性能消耗。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嘶居,一起剝皮案震驚了整個(gè)濱河市罪帖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌邮屁,老刑警劉巖整袁,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異佑吝,居然都是意外死亡坐昙,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門芋忿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)炸客,“玉大人,你說(shuō)我怎么就攤上這事戈钢”韵桑” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵殉了,是天一觀的道長(zhǎng)开仰。 經(jīng)常有香客問(wèn)我,道長(zhǎng)宣渗,這世上最難降的妖魔是什么抖所? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮痕囱,結(jié)果婚禮上田轧,老公的妹妹穿的比我還像新娘。我一直安慰自己鞍恢,他們只是感情好傻粘,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著帮掉,像睡著了一般弦悉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蟆炊,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天稽莉,我揣著相機(jī)與錄音,去河邊找鬼涩搓。 笑死污秆,一個(gè)胖子當(dāng)著我的面吹牛劈猪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播良拼,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼战得,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了庸推?” 一聲冷哼從身側(cè)響起常侦,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贬媒,沒(méi)想到半個(gè)月后聋亡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掖蛤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年杀捻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚓庭。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡致讥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出器赞,到底是詐尸還是另有隱情垢袱,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布港柜,位于F島的核電站请契,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏夏醉。R本人自食惡果不足惜爽锥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望畔柔。 院中可真熱鬧氯夷,春花似錦、人聲如沸靶擦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)玄捕。三九已至踩蔚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間枚粘,已是汗流浹背馅闽。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人捞蛋。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓孝冒,卻偏偏與公主長(zhǎng)得像柬姚,于是被迫代替她去往敵國(guó)和親拟杉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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

  • 幾天前量承,一個(gè)正在瘋狂碼代碼的午后搬设,釘釘上一個(gè)小伙伴問(wèn)我:“你知道HashMap是在什么時(shí)候做bucket的初始化的...
    miaoLoveCode閱讀 5,536評(píng)論 3 28
  • HashMap 是 Java 面試必考的知識(shí)點(diǎn),面試官?gòu)倪@個(gè)小知識(shí)點(diǎn)就可以了解我們對(duì) Java 基礎(chǔ)的掌握程度撕捍。網(wǎng)...
    野狗子嗷嗷嗷閱讀 6,657評(píng)論 9 107
  • 大腦里面裝著太多的“材料”了忧风,為了提高你的大腦思考能力默色,降低壓力,收集一切未竟之事狮腿,無(wú)論大小輕重緩急腿宰,只要是那些等...
    詩(shī)雅768閱讀 256評(píng)論 0 1
  • 安裝Php [圖片上傳中。缘厢。吃度。(1)] 安裝php擴(kuò)展
    yanghanbin_it閱讀 570評(píng)論 0 0
  • HTML----從頁(yè)面結(jié)構(gòu),語(yǔ)義上描述頁(yè)面 CSS------從審美的角度裝飾頁(yè)面 JavaScript--從交互...
    徐慕熹微閱讀 1,063評(píng)論 2 23