深入淺出HashMap

? ? ? ? HashMap作為Java的一種特殊類型戴尸,在我們的編碼過程中被廣泛使用罚拟,專門用于存放類似于(key:value)這樣的數(shù)據(jù)亿卤。它就像一個糖罐子,只是它里面每項(xiàng)數(shù)據(jù)都由兩個值組成的热凹。在HashMap出來之前泵喘,java已經(jīng)存在可以用于存放(key:value)數(shù)據(jù)類型的對象,如Dictionary和Hashtable般妙,由于他們先前設(shè)計(jì)上的缺陷纪铺,目前Dictionary已經(jīng)廢棄了,而Hashtable也不怎么使用了碟渺。目前技術(shù)條件下的編碼過程中鲜锚,如果遇到(key:value)數(shù)據(jù)類型程序員們優(yōu)先考慮使用HashMap類型。接下來我們從頂層設(shè)計(jì)開始由淺入深一步一步認(rèn)識HashMap。下圖是Hash的設(shè)計(jì)類圖:


HashMap類圖

? ? ? ? 從圖中可以看出HashMap是繼承AbstractMap芜繁,并且HashMap的存儲內(nèi)容是Entity實(shí)體組成的旺隙,且都實(shí)現(xiàn)了自己特有的方法。那么具體使用的時候HashMap數(shù)據(jù)在內(nèi)存中是如何存儲的呢骏令?啥都不說我們先看下圖:


hashMap存儲

? ? ? ? 紫色部分即代表哈希表本身(其實(shí)是一個數(shù)組)蔬捷,數(shù)組的每個元素都是一個單鏈表的頭節(jié)點(diǎn),鏈表是用來解決hash地址沖突的伏社,如果不同的key映射到了數(shù)組的同一位置處抠刺,就將其放入單鏈表中保存塔淤。HashMap設(shè)計(jì)初衷為了提升通過key獲取value的效率摘昌,所以HashMap的Entity設(shè)計(jì)初衷是通過二叉樹-紅黑樹進(jìn)行存放的,只是HashMap的內(nèi)容過多就退化為單項(xiàng)鏈表了高蜂。接下來我們?nèi)タ匆豢淳唧w操作的流程聪黎,結(jié)合程序設(shè)計(jì)的流程圖HashMap的Put操作是如何實(shí)現(xiàn)的呢?


HashMap put操作

? ? ? ? 圖中顯示了HashMap的一個Put操作的流程备恤,應(yīng)用程序的put語句的后臺實(shí)現(xiàn)原理稿饰。這里面涉及到兩個HashMap重要的操作resize-擴(kuò)容和hash值計(jì)算。接下來分別講解這兩個操作:

? ? ? ? 擴(kuò)容露泊,簡單說就是HashMap有一張Hash表喉镰,Hash表是由數(shù)組構(gòu)成,在Java中數(shù)組的初始化需要制定長度惭笑,在HashMap中默認(rèn)初始化大小為16侣姆,即只能存放16個(key:vaule)內(nèi)容。16是開發(fā)HashMap的作者根據(jù)大多應(yīng)用場景得出的能應(yīng)付多數(shù)應(yīng)用場景的值沉噩,在數(shù)據(jù)量較大且無法估計(jì)HashMap大小的場景中就需要啟用擴(kuò)容機(jī)制捺宗。HashMap每次擴(kuò)充,容量變?yōu)樵瓉淼?倍川蒙。

? ? ? ? 擴(kuò)容涉及到擴(kuò)容的兩個重要參數(shù)initialCapacityloadFactor蚜厉。initialCapacity設(shè)置初始化HashMap大小的值,默認(rèn)是16畜眨。loadFactor是加載因子昼牛,默認(rèn)是0.75。當(dāng)存儲個數(shù)threshold即size > initialCapacity *loadFactor康聂,hashmap內(nèi)部resize方法就被調(diào)用贰健。同樣initialCapacityloadFactor也可以在實(shí)例化HashMap的時候調(diào)用構(gòu)造函數(shù)進(jìn)行初始化,但需要注意一下兩點(diǎn)早抠。

1.initialCapacity容量較大霎烙,那么會使迭代器效率降低。所以理想的情況還是在使用HashMap前估計(jì)一下數(shù)據(jù)量。

2.加載因子默認(rèn)值是0.75悬垃,是JDK權(quán)衡時間和空間效率之后得到的一個相對優(yōu)良的數(shù)值游昼。如果這個值過大,雖然空間利用率是高了尝蠕,但是對于HashMap中的一些方法的效率就下降了烘豌。

? ? ? ? 根據(jù)HashMap的實(shí)現(xiàn),它在每次擴(kuò)容后的容量是原先的一倍看彼。擴(kuò)充結(jié)果都為2的冪次方大小廊佩。即HashMap總是使用2的冪作為哈希表的大小。這樣做可以成倍提升計(jì)算Hash值的效率靖榕,為什么這么說呢标锄?

? ? ? ? 因?yàn)镠ashMap大小是2的冪次方,所以它使用取模計(jì)算時茁计,可以直接使用位運(yùn)算來得到結(jié)果料皇,效率大大高于以前使用除法的效率。比如在HashMap執(zhí)行增加星压、刪除践剂、查找鍵值對時,定位到哈希位置是很關(guān)鍵的一步娜膘,源碼中是通過下面3個操作來完成這一步:1)拿到key的hashCode值逊脯;2)將hashCode的高位參與運(yùn)算,重新計(jì)算hash值竣贪;3)將計(jì)算出來的hash值與(table.length - 1)進(jìn)行&運(yùn)算军洼。

? ? ? ? 雖然使用HashMap在效率上會有提升,但是為了提升效率贾富,HashMap在實(shí)現(xiàn)過程中未進(jìn)行線程安全性限制歉眷,所以HashMap是線程不安全的。具體的線程不安全體現(xiàn)在以下兩方面:

第一颤枪,如果多個線程同時使用put方法添加元素

假設(shè)正好存在兩個put的key發(fā)生了碰撞(hash值一樣)汗捡,那么根據(jù)HashMap的實(shí)現(xiàn),這兩個key會添加到數(shù)組的同一個位置畏纲,這樣最終就會發(fā)生其中一個線程的put的數(shù)據(jù)被覆蓋扇住。

第二,如果多個線程同時檢測到元素個數(shù)超過數(shù)組大小*loadFactor

這樣會發(fā)生多個線程同時對hash數(shù)組進(jìn)行擴(kuò)容盗胀,都在重新計(jì)算元素位置以及復(fù)制數(shù)據(jù)艘蹋,但是最終只有一個線程擴(kuò)容后的數(shù)組會賦給table,也就是說其他線程的都會丟失票灰,并且各自線程put的數(shù)據(jù)也丟失女阀。且會引起死循環(huán)的錯誤宅荤。

? ? ? ? HashMap給出了他自己的解決并發(fā)辦法,多線程需要使用HashMap建議采用concurrent并發(fā)包下的concurrentHashMap浸策。

? ? ? ? 今天和大家簡單的分享了Java的HashMap冯键,當(dāng)然HashMap還有很多特性我一文不可能全部列舉完整,希望和大家一起交流學(xué)習(xí)庸汗,共同進(jìn)步惫确。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蚯舱,隨后出現(xiàn)的幾起案子改化,更是在濱河造成了極大的恐慌,老刑警劉巖枉昏,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陈肛,死亡現(xiàn)場離奇詭異,居然都是意外死亡凶掰,警方通過查閱死者的電腦和手機(jī)燥爷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來懦窘,“玉大人,你說我怎么就攤上這事稚配〕┩浚” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵道川,是天一觀的道長午衰。 經(jīng)常有香客問我,道長冒萄,這世上最難降的妖魔是什么臊岸? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮尊流,結(jié)果婚禮上帅戒,老公的妹妹穿的比我還像新娘。我一直安慰自己崖技,他們只是感情好逻住,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著迎献,像睡著了一般瞎访。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吁恍,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天扒秸,我揣著相機(jī)與錄音播演,去河邊找鬼。 笑死伴奥,一個胖子當(dāng)著我的面吹牛宾巍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播渔伯,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼顶霞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了锣吼?” 一聲冷哼從身側(cè)響起选浑,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎玄叠,沒想到半個月后古徒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡读恃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年隧膘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寺惫。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡疹吃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出西雀,到底是詐尸還是另有隱情萨驶,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布艇肴,位于F島的核電站腔呜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏再悼。R本人自食惡果不足惜核畴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望冲九。 院中可真熱鬧谤草,春花似錦、人聲如沸娘侍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽憾筏。三九已至嚎杨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氧腰,已是汗流浹背枫浙。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工刨肃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人箩帚。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓真友,卻偏偏與公主長得像,于是被迫代替她去往敵國和親紧帕。 傳聞我的和親對象是個殘疾皇子盔然,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

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

  • 實(shí)際上,HashSet 和 HashMap 之間有很多相似之處是嗜,對于 HashSet 而言愈案,系統(tǒng)采用 Hash 算...
    曹振華閱讀 2,508評論 1 37
  • HashMap 是 Java 面試必考的知識點(diǎn),面試官從這個小知識點(diǎn)就可以了解我們對 Java 基礎(chǔ)的掌握程度鹅搪。網(wǎng)...
    野狗子嗷嗷嗷閱讀 6,657評論 9 107
  • 一站绪、HashMap概述 HashMap基于哈希表的Map接口的實(shí)現(xiàn)。此實(shí)現(xiàn)提供所有可選的映射操作丽柿,并允許使用nul...
    小陳阿飛閱讀 632評論 0 2
  • 總要把自己當(dāng)主角 說著自己經(jīng)典臺詞 全是一些氣人的話 從不考慮對方感受 終于成就后來活該的頹廢 我體會了 告別時說...
    7Jun閱讀 113評論 0 0
  • 1.為什么要使用異步I/O 1.1 用戶體驗(yàn) 瀏覽器中的Javascripts是在單線程上執(zhí)行的恢准,并且和UI渲染公...
    maikuraki閱讀 535評論 0 0