HashMap筆記

HashMap

介紹

HashMap是一個以鍵值對形式保存數(shù)據(jù)的結構,實現(xiàn)了Map接口搭综,可以接受null的鍵值,內(nèi)部沒有做同步處理划栓,內(nèi)部將key的hash值兑巾,key,hash忠荞,next(下一個結點)蒋歌,包裹在一個對象中進行保存;

HashMap的工作原理

我們使用put(key,value)方法往HashMap中添加元素時钻洒,先計算得到key的Hash值奋姿,然后通過Key高16位與低16位相異或(高16位不變),然后與數(shù)組大小-1相與素标,得到了該元素在數(shù)組中的位置称诗;

如果數(shù)組中該位置為空,則直接放入头遭,如果不為空(出現(xiàn)了Hash沖突)寓免,則接到以數(shù)組該位置為鏈頭的鏈表中;

在Java8中计维,鏈表的長度超過8袜香,則使用紅黑樹來替換鏈表,以提高查找速度鲫惶;

使用get從HashMap中讀取元素時蜈首,先通過同樣的方法計算Key在數(shù)組中的下標,再通過key的equals()方法來查找對應的元素欠母;如果該位置是一個鏈表欢策,則查找的速度為O(n),如果該位置是紅黑樹赏淌,查找的時間復雜度為O(logN)踩寇;

如果HashMap的數(shù)組使用量超過了一個閾值(負載因子,默認0.75)六水,HashMap將會resize俺孙,即重新開辟一個原來數(shù)組長度兩倍的HashMap,并重新計算位置掷贾;

相關問題

  1. 為什么在resize的時候是擴展為原數(shù)組大小的兩倍睛榄?

    擴展為兩倍是為了方便重新確定元素在數(shù)組中的位置,當擴展為兩倍時想帅,數(shù)組的大小在二進制中就相當于在高位多了一位懈费,重新得到的位置要不就是在原位置,要不就是原位置加上原數(shù)組大小的位置博脑;

    因為index的計算是通過元素的hash與數(shù)組大小-1相與憎乙,數(shù)組大小-1在高位多了一位,則只需要在原來的hash的高位多取一位就是元素的index叉趣,這一位有可能是0泞边,有可能是1,是0的時候元素的位置不變疗杉,是1的時候位置相當于加了原始數(shù)組大小的位置阵谚;

    同時可以認為新增的那一位的值是隨機的,也就是可以均勻地把元素分布在新的數(shù)組中烟具;

    舉例:

    數(shù)組的大小是16: 0000 0000 0000 0000 0000 0000 0001 0000

    則數(shù)組大小減一是:0000 0000 0000 0000 0000 0000 0000 1111

    擴容后數(shù)組大小是:0000 0000 0000 0000 0000 0000 0010 0000

    數(shù)組大小減一是: 0000 0000 0000 0000 0000 0000 0001 1111

    假設元素的hash是:1111 1111 1111 1111 0000 1111 0001 0101

    原始的元素位置為:0101梢什,即為5

    擴容后的位置是:1 0101,為5 + 16 = 21

    以下是擴容的代碼(僅截取了為鏈表的部分):

    if (oldTab != null) {
        for (int j = 0; j < oldCap; ++j) {
            Node<K,V> e;
            if ((e = oldTab[j]) != null) {
                //從原始數(shù)組中取出頭結點
                oldTab[j] = null;
                //如果只有一個元素朝聋,計算出新的位置并放置
                if (e.next == null)
                    newTab[e.hash & (newCap - 1)] = e;
                //結點是樹的情況    
                else if (e instanceof TreeNode)
                    ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                else { // preserve order
                    //將該位置的元素分成兩部分嗡午,一部分為增加的一位是1的(hi),一部分為增加的一位是0的(lo)
                    Node<K,V> loHead = null, loTail = null;
                    Node<K,V> hiHead = null, hiTail = null;
                    Node<K,V> next;
                    do {
                        next = e.next;   // mark
                        //增加的一位是0
                        if ((e.hash & oldCap) == 0) {
                            //構造鏈表
                            if (loTail == null)
                                loHead = e;
                            else
                                loTail.next = e;
                            loTail = e;
                        }
                        //增加的一位是1
                        else {
                            if (hiTail == null)
                                hiHead = e;
                            else
                                hiTail.next = e;
                            hiTail = e;
                        }
                    } while ((e = next) != null);
                    //對增加的一位是0的元素進行處理
                    if (loTail != null) {
                        loTail.next = null;
                        //放置的位置為原始位置
                        newTab[j] = loHead;
                    }
                    //對增加的一位是1的元素進行處理
                    if (hiTail != null) {
                        hiTail.next = null;
                        //放置的位置為原始位置加上原始數(shù)組大小
                        newTab[j + oldCap] = hiHead;
                    }
                }
            }
        }
    }
    
  2. 在計算index時為什么要高16位與低16位異或冀痕?

    設計者為了提高在計算index時的效率荔睹,沒有采用取余(%)的方式計算index,而是采用了位運算言蛇,通過hash與數(shù)組大小-1(數(shù)組大小總是為 2^n)相與(&)得到僻他;

    但是這樣在數(shù)組較小的情況下容易產(chǎn)生Hash沖突,數(shù)組大小為16時腊尚,參與運算的只有hash的末尾4位吨拗,一共就只有15個值;

    所以在綜合考慮了速度和質(zhì)量的情況下讓高16位也參與運算婿斥,在保證效率的同時一定程度上降低了Hash沖突出現(xiàn)的可能性劝篷;

  3. HashMap是線程安全的嗎?

    不是受扳,在兩個線程同時put時會出現(xiàn)線程A的元素覆蓋線程B元素的問題;

    假設根據(jù)線程A携龟,B想要插入的元素的Key,計算得到的在數(shù)組中的index相同勘高;A線程先拿到了在那個index的鏈尾元素的引用峡蟋,這時線程A的時間片用完;線程B執(zhí)行华望,并成功地插入了元素蕊蝗,之后線程A繼續(xù)執(zhí)行,于是將鏈尾元素的引用指向了自己的元素赖舟,線程B的元素就被拋棄掉了蓬戚,造成了線程A對線程B結果的覆蓋;

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宾抓,一起剝皮案震驚了整個濱河市子漩,隨后出現(xiàn)的幾起案子豫喧,更是在濱河造成了極大的恐慌,老刑警劉巖幢泼,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件紧显,死亡現(xiàn)場離奇詭異,居然都是意外死亡缕棵,警方通過查閱死者的電腦和手機孵班,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來招驴,“玉大人篙程,你說我怎么就攤上這事”鹄澹” “怎么了虱饿?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長丹允。 經(jīng)常有香客問我郭厌,道長,這世上最難降的妖魔是什么雕蔽? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任折柠,我火速辦了婚禮,結果婚禮上批狐,老公的妹妹穿的比我還像新娘扇售。我一直安慰自己,他們只是感情好嚣艇,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布承冰。 她就那樣靜靜地躺著,像睡著了一般食零。 火紅的嫁衣襯著肌膚如雪困乒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天贰谣,我揣著相機與錄音娜搂,去河邊找鬼。 笑死吱抚,一個胖子當著我的面吹牛百宇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播秘豹,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼携御,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起啄刹,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤涮坐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后鸵膏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膊升,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年谭企,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片评肆。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡债查,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瓜挽,到底是詐尸還是另有隱情盹廷,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布久橙,位于F島的核電站俄占,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏淆衷。R本人自食惡果不足惜缸榄,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望祝拯。 院中可真熱鬧甚带,春花似錦、人聲如沸佳头。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽康嘉。三九已至碉输,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間亭珍,已是汗流浹背敷钾。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留块蚌,地道東北人闰非。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像峭范,于是被迫代替她去往敵國和親财松。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

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

  • 夢回廊閣怨四起,猶鬢鮮白貌聲衰辆毡。 黃梁獨釣心悸往菜秦,應有佳人狐媚笑。
    筆尖的靈感閱讀 125評論 0 0
  • 阿紫2 阿紫結婚后舶掖,沒多久就生了一個女兒球昨。d先生在阿紫分娩的時候沒能回去,那時正值三月眨攘,d先生在外調(diào)研主慰,回去時,阿...
    了下閱讀 401評論 0 0
  • 一切都是卑微的 獅子與螻蟻 在統(tǒng)治者的眼中 沒有區(qū)別 巴結和奉承 是它們所能做的唯一工作 清流 是絕對不存在的 一...
    四季無顏閱讀 370評論 10 25
  • 閑坐臘樹下鲫售,風過萼如雨共螺。 夏時長漫漫,悠悠能幾許? 有情慵言語情竹,知音原應稀藐不。 且駐相思意,歸往南山居秦效。
    自由和安閱讀 143評論 3 0