最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java HashMap從鏈表到紅黑樹的"進(jìn)化"過程詳解

 更新時間:2026年02月05日 11:30:15   作者:予楓的編程筆記  
在Java集合框架中,HashMap的底層實(shí)現(xiàn)在JDK 1.8迎來了一次重大革新:引入了紅黑樹,本文將結(jié)合底層源碼,帶你徹底搞懂HashMap是在什么條件下、如何進(jìn)行樹化的,感興趣的朋友跟隨小編一起看看吧

在 Java 集合框架中,HashMap 的底層實(shí)現(xiàn)在 JDK 1.8 迎來了一次重大革新:引入了紅黑樹。這一設(shè)計(jì)并非為了酷炫,而是為了解決哈希碰撞導(dǎo)致的性能退化問題。本文將結(jié)合底層源碼,帶你徹底搞懂 HashMap 是在什么條件下、如何進(jìn)行樹化的。

一、 核心源碼常量定義

HashMap.java 中,有三個關(guān)鍵常量決定了樹化與退化的閾值:

/**
 * 1. 樹化閾值:當(dāng)桶中鏈表長度大于該值時,嘗試轉(zhuǎn)為紅黑樹
 */
static final int TREEIFY_THRESHOLD = 8;
/**
 * 2. 退化閾值:當(dāng)擴(kuò)容或刪除節(jié)點(diǎn)導(dǎo)致樹節(jié)點(diǎn)數(shù)小于該值時,轉(zhuǎn)回鏈表
 */
static final int UNTREEIFY_THRESHOLD = 6;
/**
 * 3. 最小樹化容量:只有當(dāng)數(shù)組總?cè)萘看笥谠撝禃r,才會真正進(jìn)行樹化
 */
static final int MIN_TREEIFY_CAPACITY = 64;

二、 樹化的“雙重條件”深度邏輯

很多開發(fā)者只記得“鏈表長度 > 8”,但實(shí)際上源碼中存在一個隱藏的判定邏輯。

1. 觸發(fā)入口:putVal方法

當(dāng)我們在 put 一個元素時,如果發(fā)生碰撞且當(dāng)前是鏈表結(jié)構(gòu),會進(jìn)入以下邏輯:

// JDK 1.8 putVal 部分源碼
for (int binCount = 0; ; ++binCount) {
    if ((e = p.next) == null) {
        p.next = newNode(hash, key, value, null); // 插入新節(jié)點(diǎn)(尾插法)
        if (binCount >= TREEIFY_THRESHOLD - 1) // 如果鏈表長度達(dá)到 8
            treeifyBin(tab, hash); // 嘗試樹化
        break;
    }
    // ... 忽略省略部分
}

2. 核心判定:treeifyBin方法

進(jìn)入 treeifyBin 后,并不是直接轉(zhuǎn)紅黑樹,它會先檢查數(shù)組的長度:

final void treeifyBin(Node<K,V>[] tab, int hash) {
    int n, index; Node<K,V> e;
    // 【核心判定】
    // 如果數(shù)組為空,或者數(shù)組長度 n < 64,則優(yōu)先選擇擴(kuò)容而不是樹化
    if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
        resize(); 
    else if ((e = tab[index = (n - 1) & hash]) != null) {
        // 只有數(shù)組長度 ≥ 64 且鏈表長度 > 8,才會執(zhí)行真正的樹化邏輯
        // ... 將 Node 轉(zhuǎn)換為 TreeNode 的過程
    }
}

三、 深度思考:背后的數(shù)學(xué)與工程考量

1. 為什么是 8?—— 泊松分布

根據(jù) HashMap 源碼注釋,節(jié)點(diǎn)在哈希桶中的頻率遵循泊松分布。在負(fù)載因子為 0.75 的情況下,鏈表長度達(dá)到 8 的概率極低,約為 0.00000006。

設(shè)計(jì)用意:正常情況下,我們幾乎不會遇到樹化。紅黑樹是為了應(yīng)對那些哈希函數(shù)設(shè)計(jì)不佳,甚至遭受惡意哈希攻擊導(dǎo)致大量碰撞的情況。

2. 為什么退化閾值是 6 而不是 7?

這是為了留出緩沖區(qū)。如果退化閾值也是 8,那么當(dāng)一個桶的節(jié)點(diǎn)數(shù)在 7 和 8 之間反復(fù)變動時,會引起頻繁的“樹化 <-> 退化”轉(zhuǎn)換。這會導(dǎo)致大量的 TreeNodeNode 對象的創(chuàng)建與銷毀,嚴(yán)重影響性能。

3. 節(jié)點(diǎn)結(jié)構(gòu)的巨大變化

樹化不僅僅是邏輯變了,底層存儲的對象類型也發(fā)生了質(zhì)變:

  • 鏈表節(jié)點(diǎn) (Node):包含 hash, key, value, next。
  • 樹節(jié)點(diǎn) (TreeNode):繼承自 LinkedHashMap.Entry,除了基本屬性,還增加了 parent, left, right, prev, red(紅黑屬性)。

空間代價(jià)TreeNode 占用的內(nèi)存空間大約是普通 Node2 倍

四、 總結(jié):HashMap 的進(jìn)化準(zhǔn)則

鏈表轉(zhuǎn)紅黑樹:當(dāng)前桶鏈表長度

 且數(shù)組總?cè)萘?。

紅黑樹轉(zhuǎn)鏈表:在擴(kuò)容或刪除元素時,若樹中節(jié)點(diǎn)數(shù) 。

  • 核心哲學(xué)
    • 容量小、碰撞多:通過 resize 擴(kuò)容來平攤碰撞。
    • 容量大、碰撞多:通過 treeify 提升查詢效率(從 O(n) 降至 O(log n))。

?? 面試貼士

在面試中,如果面試官問:“HashMap 什么時候樹化?”,完整的回答應(yīng)該是:

“當(dāng)鏈表長度超過 8 時,HashMap 會調(diào)用 treeifyBin 方法。但該方法內(nèi)部會先判斷數(shù)組容量,如果容量小于 64,會優(yōu)先擴(kuò)容;只有容量大于等于 64 且鏈表長度達(dá)到 8,才會正式轉(zhuǎn)換為紅黑樹。”

到此這篇關(guān)于深入淺出 Java HashMap:從鏈表到紅黑樹的“進(jìn)化”之路的文章就介紹到這了,更多相關(guān)Java HashMap鏈表到紅黑樹內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring的事件監(jiān)聽機(jī)制示例詳解

    Spring的事件監(jiān)聽機(jī)制示例詳解

    這篇文章主要給大家介紹了關(guān)于Spring的事件監(jiān)聽機(jī)制的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • SpringBoot?docker項(xiàng)目部署實(shí)戰(zhàn)

    SpringBoot?docker項(xiàng)目部署實(shí)戰(zhàn)

    本文主要介紹了SpringBoot?docker項(xiàng)目部署實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • mybatis?返回Map類型key默認(rèn)為大寫問題

    mybatis?返回Map類型key默認(rèn)為大寫問題

    這篇文章主要介紹了mybatis?返回Map類型key默認(rèn)為大寫問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • springboot的類加載器(org.springframework.boot.loader)過程詳解

    springboot的類加載器(org.springframework.boot.loader)過程詳解

    這篇文章主要介紹了springboot的類加載器(org.springframework.boot.loader),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • maven?scope?provided和runtime的例子說明

    maven?scope?provided和runtime的例子說明

    這篇文章主要介紹了maven?scope?provided和runtime的例子說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 查找native方法的本地實(shí)現(xiàn)函數(shù)native_function詳解

    查找native方法的本地實(shí)現(xiàn)函數(shù)native_function詳解

    JDK開放給用戶的源碼中隨處可見Native方法,被Native關(guān)鍵字聲明的方法說明該方法不是以Java語言實(shí)現(xiàn)的,而是以本地語言實(shí)現(xiàn)的,Java可以直接拿來用。這里介紹下查找native方法的本地實(shí)現(xiàn)函數(shù)native_function,感興趣的朋友跟隨小編一起看看吧
    2021-12-12
  • 使用Get方式提交數(shù)據(jù)到Tomcat服務(wù)器的方法

    使用Get方式提交數(shù)據(jù)到Tomcat服務(wù)器的方法

    這篇文章將介紹向服務(wù)器發(fā)送數(shù)據(jù),并且服務(wù)器將數(shù)據(jù)的處理結(jié)果返回給客戶端,本文給大家介紹使用Get方式向服務(wù)器發(fā)送數(shù)據(jù),感興趣的朋友一起學(xué)習(xí)吧
    2016-04-04
  • SpringBoot中實(shí)現(xiàn)@Scheduled動態(tài)定時任務(wù)

    SpringBoot中實(shí)現(xiàn)@Scheduled動態(tài)定時任務(wù)

    SpringBoot中的@Scheduled注解為定時任務(wù)提供了一種很簡單的實(shí)現(xiàn),本文主要介紹了SpringBoot中實(shí)現(xiàn)@Scheduled動態(tài)定時任務(wù),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • 詳解JAVA的封裝

    詳解JAVA的封裝

    Java面向?qū)ο蟮娜筇匦裕悍庋b、繼承、多態(tài)。下面對三大特性之一封裝進(jìn)行了總結(jié),需要的朋友可以參考下
    2017-04-04
  • 解決@RequestBody部分屬性丟失的問題

    解決@RequestBody部分屬性丟失的問題

    這篇文章主要介紹了解決@RequestBody部分屬性丟失的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08

最新評論

安阳县| 邮箱| 宁津县| 睢宁县| 湟源县| 开平市| 正镶白旗| 竹山县| 儋州市| 韩城市| 安溪县| 石渠县| 蕉岭县| 绥阳县| 庆云县| 齐齐哈尔市| 西华县| 阜宁县| 扎赉特旗| 土默特右旗| 乐业县| 吴江市| 高阳县| 武安市| 遂溪县| 囊谦县| 新津县| 博客| 长葛市| 宾川县| 黑水县| 临海市| 锦屏县| 阳曲县| 武定县| 德兴市| 六盘水市| 镶黄旗| 如皋市| 文登市| 博罗县|