java基礎(chǔ)(HashMap理解)

HashMap其原理是底層是一個(gè)table數(shù)組+鏈表兄墅,數(shù)組的每一項(xiàng)是一個(gè)鏈表頭。當(dāng)然不同的jar包對應(yīng)的HashMap源碼還是有點(diǎn)出入的芋膘,以下以安卓的為準(zhǔn)祭钉。

而存入數(shù)組中的元素是Entry,Entry可以理解為一個(gè)封裝了key和value的對象它改,我們存進(jìn)入的其實(shí)是一個(gè)Entry對象疤孕,里面包含了key和value值。

image.png

分析一下put方法:

   public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
         return putForNullKey(value);
        int hash = sun.misc.Hashing.singleWordWangJenkinsHash(key);
        int i = indexFor(hash, table.length);
        for (HashMapEntry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(hash, key, value, i);
        return null;
}

new一個(gè)HashMap時(shí)候央拖,其實(shí)并沒有創(chuàng)建一片內(nèi)存地址祭阀,只有在put時(shí)候才會去判斷table是否為空,如果為空才創(chuàng)建鲜戒。

 if (table == EMPTY_TABLE) {
        inflateTable(threshold);
    }


 private void inflateTable(int toSize) {
    // Find a power of 2 >= toSize
    int capacity = roundUpToPowerOf2(toSize);

    // Android-changed: Replace usage of Math.min() here because this method is
    // called from the <clinit> of runtime, at which point the native libraries
    // needed by Float.* might not be loaded.
    float thresholdFloat = capacity * loadFactor;
    if (thresholdFloat > MAXIMUM_CAPACITY + 1) {
        thresholdFloat = MAXIMUM_CAPACITY + 1;
    }

    threshold = (int) thresholdFloat;
    table = new HashMapEntry[capacity];
}

put方法里面先判斷key值是否為空专控,如果是空的話,直接返回空值遏餐。

if (key == null)
return putForNullKey(value);

如果key不為空的話伦腐,通過key計(jì)算獲取到hash值
然后通過hash值獲取到數(shù)組中相應(yīng)的索引,這里要注意一下失都,如果put多個(gè)的話柏蘑,數(shù)組角標(biāo)i的值是有可能一樣的幸冻,因?yàn)閿?shù)組存的每一項(xiàng)其實(shí)也是一個(gè)鏈表頭,如果當(dāng)期數(shù)組已經(jīng)有put進(jìn)entry對象的話咳焚,那么就通過鏈表插入值洽损,采用的是頭插法。

int hash = sun.misc.Hashing.singleWordWangJenkinsHash(key);
int i = indexFor(hash, table.length);

獲取到數(shù)組角標(biāo)后黔攒,通過角標(biāo)去for循環(huán)遍歷這個(gè)角標(biāo)下的鏈表趁啸,如果是當(dāng)前key是之前已經(jīng)有插入的相同的key强缘,那么就把新值插入之前相同的key中督惰,然后把舊的value return回來

for (HashMapEntry<K,V> e = table[i]; e != null; e = e.next) {
    Object k;
     if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
     V oldValue = e.value;
      e.value = value;
      e.recordAccess(this);
      return oldValue;
      }
}

如果key是新的key的話,就新增一個(gè)entry旅掂,當(dāng)前的hash值赏胚,數(shù)值角標(biāo),key商虐,value值存進(jìn)去

ddEntry(hash, key, value, i);

分析一下get方法:

public V get(Object key) {
    if (key == null)
        return getForNullKey();
    Entry<K,V> entry = getEntry(key);
    return null == entry ? null : entry.getValue();
}


final Entry<K,V> getEntry(Object key) {
    if (size == 0) {
        return null;
    }
    int hash = (key == null) ? 0 : sun.misc.Hashing.singleWordWangJenkinsHash(key);
    for (HashMapEntry<K,V> e = table[indexFor(hash, table.length)];
         e != null;
         e = e.next) {
        Object k;
        if (e.hash == hash &&
            ((k = e.key) == key || (key != null && key.equals(k))))
            return e;
    }
    return null;
}

通過get方法可以看出觉阅,調(diào)用了getEntry方法,通過key獲取到entry對象秘车,如果對象為空典勇,只返回空值,如果對象不為空叮趴,則返回相應(yīng)的value值割笙。

Entry<K,V> entry = getEntry(key);
return null == entry ? null : entry.getValue();

重點(diǎn)要看下getEntry方法,通過源碼可以看通過key獲取到了hash值眯亦,然后通過for循環(huán)遍歷相應(yīng)數(shù)組角標(biāo)下的鏈表伤溉,判斷key值一樣,并且hash值一樣的話妻率,就返回相應(yīng)的entry對象乱顾。

 int hash = (key == null) ? 0 : sun.misc.Hashing.singleWordWangJenkinsHash(key);
    for (HashMapEntry<K,V> e = table[indexFor(hash, table.length)];
         e != null;
         e = e.next) {
        Object k;
        if (e.hash == hash &&
            ((k = e.key) == key || (key != null && key.equals(k))))
            return e;
    }

而且遍歷是從鏈表頭開始遍歷的,這也說明了越后面的put進(jìn)去的值被找到的時(shí)間越短宫静。

關(guān)于擴(kuò)容問題

從源碼中可以看出在put里面的addEntry方法進(jìn)行判斷走净,當(dāng)數(shù)組不為空或者put數(shù)量(size)大于16個(gè)時(shí)候,就會進(jìn)行擴(kuò)容孤里,擴(kuò)容了一倍伏伯。

  void addEntry(int hash, K key, V value, int bucketIndex) {
    if ((size >= threshold) && (null != table[bucketIndex])) {
        resize(2 * table.length);
        hash = (null != key) ? sun.misc.Hashing.singleWordWangJenkinsHash(key) : 0;
        bucketIndex = indexFor(hash, table.length);
    }

    createEntry(hash, key, value, bucketIndex);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市扭粱,隨后出現(xiàn)的幾起案子舵鳞,更是在濱河造成了極大的恐慌,老刑警劉巖琢蛤,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜓堕,死亡現(xiàn)場離奇詭異抛虏,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)套才,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門迂猴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人背伴,你說我怎么就攤上這事沸毁。” “怎么了傻寂?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵息尺,是天一觀的道長。 經(jīng)常有香客問我疾掰,道長搂誉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任静檬,我火速辦了婚禮炭懊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拂檩。我一直安慰自己侮腹,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布稻励。 她就那樣靜靜地躺著父阻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪钉迷。 梳的紋絲不亂的頭發(fā)上至非,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機(jī)與錄音糠聪,去河邊找鬼荒椭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛舰蟆,可吹牛的內(nèi)容都是我干的趣惠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼身害,長吁一口氣:“原來是場噩夢啊……” “哼味悄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起塌鸯,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤侍瑟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涨颜,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡费韭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了庭瑰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片星持。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖弹灭,靈堂內(nèi)的尸體忽然破棺而出督暂,到底是詐尸還是另有隱情,我是刑警寧澤穷吮,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布逻翁,位于F島的核電站,受9級特大地震影響酒来,放射性物質(zhì)發(fā)生泄漏卢未。R本人自食惡果不足惜肪凛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一堰汉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧伟墙,春花似錦翘鸭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拱烁,卻和暖如春生蚁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背戏自。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工邦投, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人擅笔。 一個(gè)月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓志衣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親猛们。 傳聞我的和親對象是個(gè)殘疾皇子念脯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

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

  • 一绿店、基本數(shù)據(jù)類型 注釋 單行注釋:// 區(qū)域注釋:/* */ 文檔注釋:/** */ 數(shù)值 對于byte類型而言...
    龍貓小爺閱讀 4,261評論 0 16
  • 5.1、對于HashMap需要掌握以下幾點(diǎn) Map的創(chuàng)建:HashMap() 往Map中添加鍵值對:即put(Ob...
    rochuan閱讀 678評論 0 0
  • 在這本書里東野圭吾讓“神探伽利略”湯川遇到了比《嫌疑人X的獻(xiàn)身》更難破解的迷局:“這種事只在理論上可行庐橙,現(xiàn)實(shí)中幾乎...
    智慧糖屋閱讀 372評論 0 0
  • NO5 4-10 臨沂營作業(yè) R· 閱讀原文片段 1 請寫下你的目標(biāo) 例一:我的目標(biāo)是在工作表現(xiàn)中領(lǐng)先假勿。 例二:我...
    豪_豪閱讀 162評論 1 0
  • 木南_1982閱讀 173評論 0 2