HashMap 源碼分析

構(gòu)造函數(shù)

HashMap 提供了三個(gè)構(gòu)造函數(shù)和一個(gè)拷貝構(gòu)造函數(shù):

public HashMap(int initialCapacity, float loadFactor);

public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

public HashMap() {
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
    }

public HashMap(Map<? extends K, ? extends V> m);

構(gòu)造函數(shù)

/**
 * Constructs an empty <tt>HashMap</tt> with the specified initial
 * capacity and load factor.
 *
 * @param  initialCapacity the initial capacity
 * @param  loadFactor      the load factor
 * @throws IllegalArgumentException if the initial capacity is negative
 *         or the load factor is nonpositive
 */
public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " +
                                           initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY) {
        initialCapacity = MAXIMUM_CAPACITY;
    } else if (initialCapacity < DEFAULT_INITIAL_CAPACITY) {
        initialCapacity = DEFAULT_INITIAL_CAPACITY;
    }

    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " +
                                           loadFactor);
    // Android-Note: We always use the default load factor of 0.75f.

    // This might appear wrong but it's just awkward design. We always call
    // inflateTable() when table == EMPTY_TABLE. That method will take "threshold"
    // to mean "capacity" and then replace it with the real threshold (i.e, multiplied with
    // the load factor).
    threshold = initialCapacity;
    init();
}

這個(gè)構(gòu)造方法需要提供兩個(gè)參數(shù),initialCapacityloadFactor 嚷炉。

  • 第一個(gè)參數(shù)表示 hashMap 的初始化大小哟旗,默認(rèn)值為 static final int DEFAULT_INITIAL_CAPACITY = 4; 碟联,且 初始化大小的值必須是 2 的整數(shù)次冪脑豹。
  • 第二個(gè)參數(shù)表示 todo

在構(gòu)造方法中抗愁,首先對(duì)初始化大小 initialCapacity 進(jìn)行校正馁蒂,校正范圍是 4(默認(rèn)初始化大小) ~ 2^30(最大容量)。

HashMapEntry

static class HashMapEntry<K,V> implements Map.Entry<K,V> {
    final K key;
    V value;
    HashMapEntry<K,V> next;
    int hash;
   }

HashMapEntry 中保存著一個(gè) Key 和 Value 蜘腌,并持有下一個(gè) HashMapEntry 远搪,很明顯這是一個(gè) <K-V> 鍵值對(duì)鏈表。

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

put 方法

/**
 * Associates the specified value with the specified key in this map.
 * If the map previously contained a mapping for the key, the old
 * value is replaced.
 *
 * @param key key with which the specified value is to be associated
 * @param value value to be associated with the specified key
 * @return the previous value associated with <tt>key</tt>, or
 *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
 *         (A <tt>null</tt> return can also indicate that the map
 *         previously associated <tt>null</tt> with <tt>key</tt>.)
 */
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;
}
  • 從上面代碼可以看出逢捺,HashMap 的 Key 是可以為 null 的,在 key == null 的情況下癞季,調(diào)用 putForNullKey() 方法特殊處理
  • 正常的情況下劫瞳,現(xiàn)根據(jù) key 的值計(jì)算出 hash 值,并計(jì)算出該 hash 值在隊(duì)列中的 index绷柒。在 table 數(shù)組中取出 HashMapEntry 的鏈表志于,并進(jìn)行遍歷,如果 hash 值相同且 Key 也相同废睦,說(shuō)明新插入的 Key 在 鏈表中存在伺绽,需要覆蓋舊值,并返回舊值嗜湃。如果沒(méi)有找到奈应,說(shuō)明這個(gè) Key 并不存在,需要調(diào)用 addEntry 添加在 HashMapEntry 的鏈表中购披。
**
 * Adds a new entry with the specified key, value and hash code to
 * the specified bucket.  It is the responsibility of this
 * method to resize the table if appropriate.
 *
 * Subclass overrides this to alter the behavior of put method.
 */
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);
}

從 addEntry 方法的實(shí)現(xiàn)可以看出杖挣,當(dāng)此時(shí) hashmap 的 size 大于等于閾值時(shí),需要將 table 的長(zhǎng)度擴(kuò)大一倍刚陡,并調(diào)用 createEntry() 方法根據(jù)新 Key 的 hash 值 存儲(chǔ)在 table 中惩妇。

/**
 * Like addEntry except that this version is used when creating entries
 * as part of Map construction or "pseudo-construction" (cloning,
 * deserialization).  This version needn't worry about resizing the table.
 *
 * Subclass overrides this to alter the behavior of HashMap(Map),
 * clone, and readObject.
 */
void createEntry(int hash, K key, V value, int bucketIndex) {
    HashMapEntry<K,V> e = table[bucketIndex];
    table[bucketIndex] = new HashMapEntry<>(hash, key, value, e);
    size++;
}

將 table 中 index = bucketIndex 的 HashMapEntry 作為新節(jié)點(diǎn)的下一個(gè) Entry 株汉,并將 table[bucketIndex] 指向新節(jié)點(diǎn)。

get 方法

get 方法的思想就是利用 key 的 hash 值獲得在 table 中所處的 index 歌殃,并對(duì)其進(jìn)行遍歷乔妈,比較 Key 將對(duì)應(yīng)的 Value 取出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末氓皱,一起剝皮案震驚了整個(gè)濱河市路召,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌匀泊,老刑警劉巖优训,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異各聘,居然都是意外死亡揣非,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門躲因,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)早敬,“玉大人,你說(shuō)我怎么就攤上這事大脉「慵啵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵镰矿,是天一觀的道長(zhǎng)琐驴。 經(jīng)常有香客問(wèn)我,道長(zhǎng)秤标,這世上最難降的妖魔是什么绝淡? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮苍姜,結(jié)果婚禮上牢酵,老公的妹妹穿的比我還像新娘。我一直安慰自己衙猪,他們只是感情好馍乙,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著垫释,像睡著了一般丝格。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上饶号,一...
    開(kāi)封第一講書(shū)人閱讀 49,821評(píng)論 1 290
  • 那天铁追,我揣著相機(jī)與錄音,去河邊找鬼茫船。 笑死琅束,一個(gè)胖子當(dāng)著我的面吹牛扭屁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涩禀,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼料滥,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了艾船?” 一聲冷哼從身側(cè)響起葵腹,我...
    開(kāi)封第一講書(shū)人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎屿岂,沒(méi)想到半個(gè)月后践宴,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡爷怀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年阻肩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片运授。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡烤惊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吁朦,到底是詐尸還是另有隱情柒室,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布逗宜,位于F島的核電站雄右,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏纺讲。R本人自食惡果不足惜不脯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望刻诊。 院中可真熱鬧,春花似錦牺丙、人聲如沸则涯。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)粟判。三九已至,卻和暖如春峦剔,著一層夾襖步出監(jiān)牢的瞬間档礁,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工吝沫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留呻澜,地道東北人递礼。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像羹幸,于是被迫代替她去往敵國(guó)和親脊髓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

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

  • HashMap 是 Java 面試必考的知識(shí)點(diǎn)栅受,面試官?gòu)倪@個(gè)小知識(shí)點(diǎn)就可以了解我們對(duì) Java 基礎(chǔ)的掌握程度将硝。網(wǎng)...
    野狗子嗷嗷嗷閱讀 6,661評(píng)論 9 107
  • 最近一直特別忙,好不容易閑下來(lái)了。準(zhǔn)備把HashMap的知識(shí)總結(jié)一下屏镊,很久以前看過(guò)HashMap源碼依疼。一直想把集...
    鵬_鵬閱讀 473評(píng)論 0 3
  • JAVA 8 HashMap 源碼分析 一 什么是HashMap? HashMap 繼承了AbstractMap,...
    gdutkyle閱讀 465評(píng)論 0 1
  • 一、基本數(shù)據(jù)類型 注釋 單行注釋:// 區(qū)域注釋:/* */ 文檔注釋:/** */ 數(shù)值 對(duì)于byte類型而言...
    龍貓小爺閱讀 4,257評(píng)論 0 16
  • 在寫(xiě)下這篇之前蔚出,我已經(jīng)想了好幾個(gè)月關(guān)于怎樣做父母這件事兒弟翘,但一直沒(méi)有頭緒,而在我提筆之前骄酗,關(guān)于這個(gè)標(biāo)題也猶豫...
    胡小鬧不胡鬧閱讀 275評(píng)論 0 0