欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中HashMap的put過程詳解

 更新時間:2023年07月25日 11:25:44   作者:「已注銷」  
這篇文章主要介紹了Java中HashMap的put過程詳解,HashMap有4個構(gòu)造器,其他構(gòu)造器如果用戶沒有傳入initialCapacity?和loadFactor這兩個參數(shù),會使用默認(rèn)值一般如果new?HashMap()不傳值,需要的朋友可以參考下

HashMap put過程

初始化

HashMap有4個構(gòu)造器,其他構(gòu)造器如果用戶沒有傳入initialCapacity 和loadFactor這兩個參數(shù),會使用默認(rèn)值一般如果new HashMap() 不傳值,默認(rèn)大小是16,負(fù)載因子是0.75, 如果自己傳入初始大小k,初始化大小為 大于k的 2的整數(shù)次方,例如如果傳10,大小為16。

put()過程

判斷數(shù)組是否為空,為空進(jìn)行初始化; 不為空,計算 key的 hash 值,通過(n - 1) & hash(記不住就直接說哈希算法)計算應(yīng)當(dāng)存放在數(shù)組中的下標(biāo) index;查看 table[index] 是否存在數(shù)據(jù),沒有數(shù)據(jù)就構(gòu)造一個Node節(jié)點存放在 table[index] 中;存在數(shù)據(jù),說明發(fā)生了hash沖突(存在兩個節(jié)點key的hash值一樣), 繼續(xù)判斷key是否相等,相等,用新的value替換原數(shù)據(jù)(onlyIfAbsent為false); 如果不相等,判斷當(dāng)前節(jié)點類型是不是樹型節(jié)點,如果是樹型節(jié)點,創(chuàng)造樹型節(jié)點插入紅黑樹中;(如果當(dāng)前節(jié)點是樹型節(jié)點證明當(dāng)前已經(jīng)是紅黑樹了) 如果不是樹型節(jié)點,創(chuàng)建普通Node加入鏈表中;判斷鏈表長度是否大于 8并且數(shù)組長度大于64, 大于的話鏈表轉(zhuǎn)換為紅黑樹;

插入完成之后判斷當(dāng)前節(jié)點數(shù)是否大于閾值,如果大于開始擴容為原數(shù)組的二倍。

image20210828210330896

// put源碼
public V put(K key, V value) {
        //如果table數(shù)組為空數(shù)組{},進(jìn)行數(shù)組填充(為table分配實際內(nèi)存空間),入?yún)閠hreshold,
        //此時threshold為initialCapacity 默認(rèn)是1<<4(2^4=16)
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
       //如果key為null,存儲位置為table[0]或table[0]的沖突鏈上
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);//對key的hashcode進(jìn)一步計算,確保散列均勻
        int i = indexFor(hash, table.length);//獲取在table中的實際位置
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        //如果該對應(yīng)數(shù)據(jù)已存在,執(zhí)行覆蓋操作。用新value替換舊value,并返回舊value
            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++;//保證并發(fā)訪問時,若HashMap內(nèi)部結(jié)構(gòu)發(fā)生變化,快速響應(yīng)失敗
        addEntry(hash, key, value, i);//新增一個entry
        return null;
    }

inflateTable這個方法用于為主干數(shù)組table在內(nèi)存中分配存儲空間,通過roundUpToPowerOf2(toSize)可以確保capacity為大于或等于toSize的最接近toSize的二次冪,比如toSize=13,則capacity=16;to_size=16,capacity=16;to_size=17,capacity=32.

void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);//當(dāng)size超過臨界閾值threshold,并且即將發(fā)生哈希沖突時進(jìn)行擴容
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }
        createEntry(hash, key, value, bucketIndex);
    }

通過以上代碼能夠得知,當(dāng)發(fā)生哈希沖突并且size大于閾值(threshold)的時候,需要進(jìn)行數(shù)組擴容,擴容時,需要新建一個長度為之前數(shù)組2倍的新的數(shù)組,然后將當(dāng)前的Entry數(shù)組中的元素全部傳輸過去,擴容后的新數(shù)組長度為之前的2倍,所以擴容相對來說是個耗資源的操作。

為什么HashMap數(shù)組長度一定要是2的n次冪

計算索引位置的公式為:(n - 1) & hash,當(dāng) n 為 2 的 N 次方時,n - 1 為低位全是 1 的值,此時任何值跟 n - 1 進(jìn)行 & 運算的結(jié)果為該值的低 N 位,達(dá)到了和取模同樣的效果,實現(xiàn)了均勻分布。實際上,這個設(shè)計就是基于公式:x mod 2^n = x & (2^n - 1),因為 & 運算比 mod 具有更高的效率 總的來說原因是2^n-1的低位是1,在進(jìn)行與運算時更加高效,同時還可以降低hash沖突

什么時候轉(zhuǎn)紅黑樹

因為當(dāng)桶中元素到達(dá)8個的時候,概率已經(jīng)變得非常小,也就是說用0.75作為負(fù)載因子,每個碰撞位置的鏈表長度超過8個是幾乎不可能的(概率極小)。(也就是超過8 可以轉(zhuǎn)化為紅黑樹)

  • 并且如果 鏈表的長度 大于 8 會嘗試調(diào)用 treeifyBin 方法
  • 再判斷表的長度是否大于64

在鏈表長度大于 8 并且 表的長度大于 64 的時候會轉(zhuǎn)化紅黑樹?。。?!

if ((e = p.next) == null) {
    p.next = newNode(hash, key, value, null);
    // 并且如果 鏈表的長度 大于 8 會嘗試調(diào)用  treeifyBin 方法
    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
        treeifyBin(tab, hash);
    break;
}
// treeifyBin 方法
    final void treeifyBin(Node<K,V>[] tab, int hash) {
        int n, index; Node<K,V> e;
        // 如果表的長度小于 64 會先擴容?。?! 否則 擴容
        // MIN_TREEIFY_CAPACITY = 64;
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();
        else if ((e = tab[index = (n - 1) & hash]) != null) {
            TreeNode<K,V> hd = null, tl = null;
            do {
                TreeNode<K,V> p = replacementTreeNode(e, null);
                if (tl == null)
                    hd = p;
                else {
                    p.prev = tl;
                    tl.next = p;
                }
                tl = p;
            } while ((e = e.next) != null);
            if ((tab[index] = hd) != null)
                hd.treeify(tab);
        }
    }

為什么鏈表閾值是8

我們平時在進(jìn)行方案設(shè)計時,必須考慮的兩個很重要的因素是:時間和空間。對于 HashMap 也是同樣的道理,簡單來說,閾值為8是在時間和空間上權(quán)衡的結(jié)果。

科學(xué)解釋

理想情況下,使用隨機的哈希碼,節(jié)點分布在 hash 桶中的頻率遵循泊松分布,按照泊松分布的公式計算,鏈表中節(jié)點個數(shù)為8時的概率為 0.00000006(跟大樂透一等獎差不多,中大樂透?不存在的),這個概率足夠低了,并且到8個節(jié)點時,紅黑樹的性能優(yōu)勢也會開始展現(xiàn)出來,因此8是一個較合理的數(shù)字。

那為什么紅黑樹轉(zhuǎn)回鏈表是6

因為中間多個個7,不會使得紅黑樹和鏈表之間頻繁轉(zhuǎn)換,如果我們設(shè)置節(jié)點多于8個轉(zhuǎn)紅黑樹,少于8個就馬上轉(zhuǎn)鏈表,當(dāng)節(jié)點個數(shù)在8徘徊時,就會頻繁進(jìn)行紅黑樹和鏈表的轉(zhuǎn)換,造成性能的損耗

到此這篇關(guān)于Java中HashMap的put過程詳解的文章就介紹到這了,更多相關(guān)ashMap的put內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot使用@Autowired為多實現(xiàn)的接口注入依賴

    SpringBoot使用@Autowired為多實現(xiàn)的接口注入依賴

    這篇文章主要介紹了SpringBoot使用@Autowired為多實現(xiàn)的接口注入依賴,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • springboot自定義starter方法及注解實例

    springboot自定義starter方法及注解實例

    這篇文章主要為大家介紹了springboot自定義starter方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • java system類使用方法示例 獲取系統(tǒng)信息

    java system類使用方法示例 獲取系統(tǒng)信息

    這篇文章主要介紹了java system類使用方法,該類中的方法都是靜態(tài)的。不能被實例化,沒有對外提供構(gòu)造函數(shù),該類可以獲取系統(tǒng)信息
    2014-01-01
  • Java 替換空格

    Java 替換空格

    本文主要介紹了Java中替換空格的方法。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-01-01
  • Java實現(xiàn)浪漫流星表白的示例代碼

    Java實現(xiàn)浪漫流星表白的示例代碼

    本文將利用Java語言實現(xiàn)浪漫流星表白,可以實現(xiàn)這些功能:播放音樂、自定義流星數(shù)量、飛行速度、光暈大小、流星大小,自定義表白話語,感興趣的可以學(xué)習(xí)一下
    2022-05-05
  • Java類和對象習(xí)題及詳細(xì)答案解析

    Java類和對象習(xí)題及詳細(xì)答案解析

    這篇文章主要介紹了Java類和對象的相關(guān)知識,包括局部變量初始化、靜態(tài)方法、靜態(tài)導(dǎo)入、構(gòu)造方法、代碼塊執(zhí)行順序、toString方法重寫、類變量和靜態(tài)成員變量的訪問等,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-02-02
  • Jpa?Specification如何實現(xiàn)and和or同時使用查詢

    Jpa?Specification如何實現(xiàn)and和or同時使用查詢

    這篇文章主要介紹了Jpa?Specification如何實現(xiàn)and和or同時使用查詢,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java實現(xiàn)簡單的webservice方式

    java實現(xiàn)簡單的webservice方式

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)簡單的webservice方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 如何用Dos命令運行Java版HelloWorld你知道嗎

    如何用Dos命令運行Java版HelloWorld你知道嗎

    這篇文章主要介紹了在dos窗口中編譯和運行java文件的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08
  • java實現(xiàn)水波紋擴散效果

    java實現(xiàn)水波紋擴散效果

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)水波紋擴散效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01

最新評論