HashMap原理

public V put(K key, V value) {
        return this.putVal(hash(key), key, value, false, true);
    }

   static final int hash(Object key) {
        int h;
        return key == null ? 0 : (h = key.hashCode()) ^ h >>> 16;
    }

2.執(zhí)行putValu進(jìn)行值計(jì)算

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict)

1.校驗(yàn)table是否為空或者length等于0,如果是則調(diào)用resize方法進(jìn)行初始化

    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;

2.通過hash值計(jì)算索引位置,將該索引位置的頭節(jié)點(diǎn)賦值給p,如果p為空則直接在該索引位置新增一個(gè)節(jié)點(diǎn)即可

   if ((p = tab[i = (n - 1) & hash]) == null)
     tab[i] = newNode(hash, key, value, null);

3.判斷p節(jié)點(diǎn)的key和hash值是否跟傳入的相等,如果相等, 則p節(jié)點(diǎn)即為要查找的目標(biāo)節(jié)點(diǎn),將p節(jié)點(diǎn)賦值給e節(jié)點(diǎn)

       if (p.hash == hash &&
           ((k = p.key) == key || (key != null && key.equals(k))))
           e = p;

4.判斷p節(jié)點(diǎn)是否為TreeNode, 如果是則調(diào)用紅黑樹的putTreeVal方法查找目標(biāo)節(jié)點(diǎn)

       else if (p instanceof TreeNode)
           e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);

5.走到這代表p節(jié)點(diǎn)為普通鏈表節(jié)點(diǎn),則調(diào)用普通的鏈表方法進(jìn)行查找,使用binCount統(tǒng)計(jì)鏈表的節(jié)點(diǎn)數(shù)

for (int binCount = 0; ; ++binCount){}
        else {
       走到這代表p節(jié)點(diǎn)為普通鏈表節(jié)點(diǎn),則調(diào)用普通的鏈表方法進(jìn)行查找,使用binCount統(tǒng)計(jì)鏈表的節(jié)點(diǎn)數(shù)
            for (int binCount = 0; ; ++binCount) {
                // 6.如果p的next節(jié)點(diǎn)為空時(shí),則代表找不到目標(biāo)節(jié)點(diǎn),則新增一個(gè)節(jié)點(diǎn)并插入鏈表尾部
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    // 7.校驗(yàn)節(jié)點(diǎn)數(shù)是否超過8個(gè),如果超過則調(diào)用treeifyBin方法將鏈表節(jié)點(diǎn)轉(zhuǎn)為紅黑樹節(jié)點(diǎn),
                    // 減一是因?yàn)檠h(huán)是從p節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)開始的
                    if (binCount >= TREEIFY_THRESHOLD - 1)
                        treeifyBin(tab, hash);
                    break;
                }
                // 8.如果e節(jié)點(diǎn)存在hash值和key值都與傳入的相同,則e節(jié)點(diǎn)即為目標(biāo)節(jié)點(diǎn),跳出循環(huán)
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;  // 將p指向下一個(gè)節(jié)點(diǎn)
            }
        }
        // 9.如果e節(jié)點(diǎn)不為空,則代表目標(biāo)節(jié)點(diǎn)存在,使用傳入的value覆蓋該節(jié)點(diǎn)的value,并返回oldValue
        if (e != null) {
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e); // 用于LinkedHashMap
            return oldValue;
        }
    }
    ++modCount;
    // 10.如果插入節(jié)點(diǎn)后節(jié)點(diǎn)數(shù)超過閾值,則調(diào)用resize方法進(jìn)行擴(kuò)容
    if (++size > threshold)
        resize();

執(zhí)行g(shù)et方法,如果是紅黑樹,則調(diào)用紅黑樹的查找目標(biāo)節(jié)點(diǎn)方法getTreeNode

public V get(Object key) {
    Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}
 
final Node<K,V> getNode(int hash, Object key) {
    Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
    // 1.對(duì)table進(jìn)行校驗(yàn):table不為空 && table長度大于0 && 
    // table索引位置(使用table.length - 1和hash值進(jìn)行位與運(yùn)算)的節(jié)點(diǎn)不為空
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & hash]) != null) {
        // 2.檢查first節(jié)點(diǎn)的hash值和key是否和入?yún)⒌囊粯?,如果一樣則first即為目標(biāo)節(jié)點(diǎn),直接返回first節(jié)點(diǎn)
        if (first.hash == hash && // always check first node
            ((k = first.key) == key || (key != null && key.equals(k))))
            return first;
        // 3.如果first不是目標(biāo)節(jié)點(diǎn),并且first的next節(jié)點(diǎn)不為空則繼續(xù)遍歷
        if ((e = first.next) != null) {
            if (first instanceof TreeNode)
                // 4.如果是紅黑樹節(jié)點(diǎn),則調(diào)用紅黑樹的查找目標(biāo)節(jié)點(diǎn)方法getTreeNode
                return ((TreeNode<K,V>)first).getTreeNode(hash, key);
            do {
                // 5.執(zhí)行鏈表節(jié)點(diǎn)的查找,向下遍歷鏈表, 直至找到節(jié)點(diǎn)的key和入?yún)⒌膋ey相等時(shí),返回該節(jié)點(diǎn)
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    // 6.找不到符合的返回空
    return null;
}

3.DEFAULT_INITIAL_CAPACITY=16?
在線位運(yùn)算
在線二進(jìn)制轉(zhuǎn)換

以下僅演示低4位的位運(yùn)算,其實(shí)在jdk1.8的時(shí)候位把高28位的運(yùn)算都加入,以此來降低hash沖突的概率


如果length默認(rèn)是16,那么length-1=15,執(zhí)行下面的與運(yùn)算
h&length-1
 
    15 二進(jìn)制:  1111
&   0  二進(jìn)制:  0000
----------------------------
               1111
====================
    15 二進(jìn)制:  1111
&   1  二進(jìn)制:  0001
----------------------------
               1110          


如果length默認(rèn)是15,那么length-1=14,執(zhí)行下面的與運(yùn)算
h&length-1
 
    14 二進(jìn)制:  1110
&   0  二進(jìn)制:  0000
----------------------------
               1110--------------------------->1110跟下面這個(gè)值一樣
==================== 
    14 二進(jìn)制:  1110
&   1  二進(jìn)制:  0001
----------------------------
               1110--------------------------->1110跟上面這個(gè)值一樣                

綜上分析,如果默認(rèn)值不是16,或者說不是2的冪指數(shù),那么執(zhí)行位運(yùn)算之后,得出的結(jié)果可能是相同的,也就是哈希碰撞的概率變高

3.TreeNode 紅黑樹(高性能的平衡樹)來保存沖突節(jié)點(diǎn)O(n)->提高到O(logn)

可以考慮下時(shí)間復(fù)雜度是怎么計(jì)算的,這里備注下

4.是否每一個(gè)節(jié)點(diǎn)都是紅黑樹?

不是,為了效率更高,并不會(huì)直接每個(gè)節(jié)點(diǎn)都使用紅黑樹,因?yàn)榧t黑樹的初始化復(fù)雜,而且有很多的左旋右旋,本身來說,構(gòu)建復(fù)雜耗時(shí)。
當(dāng)節(jié)點(diǎn)超過8的時(shí)候,才會(huì)轉(zhuǎn)成紅黑樹
目的就是為了讓查找效率跟高效

5.HashMap線程安全問題

多線程插入、刪除、擴(kuò)充操作數(shù)據(jù)的時(shí)候,會(huì)有多線程安全問題,
可以參考HashTable實(shí)現(xiàn)策略
或者SparseArray

6.HashTable 源碼分析

基本來說就是把整個(gè)HashMap加了鎖,其他跟HashMap基本一致

7.ConcurrentHashMap跟HashTable、HashMap區(qū)別

鎖的范圍精確到對(duì)應(yīng)鏈表,而不是整個(gè)HashMap

7.SparseArray 源碼分析 跟HashMap區(qū)別

8.HashMap為什么會(huì)發(fā)生死循環(huán)
https://baijiahao.baidu.com/s?id=1675991555833901875&wfr=spider&for=pc

待總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容