拆分了解HashMap的數據結構

文章目錄

前言

一、底層數據結構總覽

二、核心組成部分詳解

1. 數組(哈希表)

2. 節點(Node)

3. 紅黑樹(TreeNode)

三、哈希函數與索引計算

四、哈希沖突的解決

五、擴容機制

六、關鍵特性與注意事項

總結


前言

????????在 Java 開發中,HashMap 是高頻使用的集合類,從業務緩存到框架底層都離不開它,但多數開發者對其理解僅停留在 “鍵值對存儲”,對 “為何高效”“為何踩坑” 的底層邏輯一知半解。

????????面試中 “JDK1.7 與 1.8 的 HashMap 有何不同”“鏈表為何轉紅黑樹”,開發中 “擴容導致性能波動”“哈希沖突引發查詢變慢”,這些問題的答案,都藏在 HashMap 的底層設計里。它不是簡單的 “數組 + 鏈表”,而是融合哈希算法、動態擴容、紅黑樹的復雜體系,每處細節都是 “時間與空間的權衡”。

????????本文將拆解 HashMap 的核心設計:從結構演進(數組 + 鏈表→數組 + 鏈表 + 紅黑樹),到哈希沖突解決、擴容邏輯、紅黑樹轉換,再到 key 的規范細節。無論你是新手還是資深工程師,都能理清設計邏輯,既應對面試考點,也能在開發中合理調優,寫出更高效的代碼。接下來,我們從 HashMap 的底層結構開始,逐層剖析。


HashMap 是 Java 集合框架中常用的實現類(實現?Map?接口),用于存儲鍵值對(key-value)數據,其核心特點是查詢、插入、刪除效率高(平均時間復雜度為 O (1)),底層通過數組 + 鏈表 + 紅黑樹的復合數據結構實現,這種設計是為了平衡哈希沖突帶來的性能問題。

一、底層數據結構總覽

HashMap 在 JDK 1.8 中進行了重大優化,核心差異如下:

JDK 1.8 及之后,HashMap 的底層結構由三部分組成:

特性JDK 1.7JDK 1.8
底層結構數組 + 鏈表數組 + 鏈表 + 紅黑樹
鏈表插入方式頭插法(新節點插入鏈表頭部)尾插法(新節點插入鏈表尾部)
擴容時的 rehash需要重新計算所有節點的索引利用高位判斷,減少計算量
沖突處理效率鏈表查詢時間復雜度 O (n)紅黑樹查詢時間復雜度 O (log n)
關鍵常量無紅黑樹相關閾值引入樹化閾值(8)、鏈化閾值(6)
  • 數組(核心容器):稱為「哈希表」或「桶(Bucket)」,是 HashMap 的主體,數組中的每個元素是一個「節點」(Node)。
  • 鏈表:當哈希沖突時,相同索引位置的節點會以鏈表形式存儲。
  • 紅黑樹:當鏈表長度超過閾值(默認 8)且數組長度 ≥ 64 時,鏈表會轉為紅黑樹,以優化查詢效率(紅黑樹查詢時間復雜度為 O (log n),優于鏈表的 O (n))。

結構示意圖如下:

數組索引: 0   1   2        3        ...  n-1|   |   |        |v   v   v        v
節點:   Node Node Node -> Node -> ...  Node|vTreeNode (紅黑樹節點)

二、核心組成部分詳解

1. 數組(哈希表)
  • 作用:作為底層容器,直接存儲節點(Node),數組的長度稱為「容量(Capacity)」。
  • 容量特性:默認初始容量為 16,且始終保持為 2 的冪次方(如 16、32、64...)。這是為了通過「與運算」高效計算索引(替代取模運算),同時保證哈希值分布更均勻。
  • 索引計算:數組索引由 key 的哈希值通過計算得到,公式簡化為:index = (n - 1) & hash(n 為數組長度,hash 為 key 的哈希值經過擾動處理后的值)。
2. 節點(Node)

數組中的元素是?Node?對象,實現?Map.Entry?接口,包含四個核心字段:

static class Node<K,V> implements Map.Entry<K,V> {final int hash;    // key 的哈希值(經過擾動處理)final K key;       // 鍵(不可變)V value;           // 值(可變)Node<K,V> next;    // 下一個節點的引用(用于鏈表)
}
  • hash:用于定位節點在數組中的索引。
  • next:當發生哈希沖突時,通過該字段形成鏈表(指向同索引下的下一個節點)。
3. 紅黑樹(TreeNode)

當鏈表長度超過閾值(默認 8)且數組長度 ≥ 64 時,鏈表會轉為紅黑樹(TreeNode?繼承?Node),以優化查詢性能。TreeNode?額外包含紅黑樹的核心字段:

static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {TreeNode<K,V> parent;  // 父節點TreeNode<K,V> left;    // 左子節點TreeNode<K,V> right;   // 右子節點TreeNode<K,V> prev;    // 前一個節點(用于回退為鏈表)boolean red;           // 節點顏色(紅/黑)
}
  • 紅黑樹是一種自平衡二叉搜索樹,通過保持「黑色平衡」確保樹的高度穩定(約為 log n),避免鏈表過長導致的查詢效率下降。
  • 當紅黑樹節點數減少到 6 時,會重新轉為鏈表(平衡查詢和插入效率)。

三、哈希函數與索引計算

HashMap 通過哈希函數將 key 映射到數組索引,核心目的是讓 key 均勻分布在數組中,減少哈希沖突。步驟如下:

  1. 計算 key 的原始哈希值:調用?key.hashCode(),得到一個 32 位整數(不同 key 可能返回相同值,即「哈希碰撞」)。

  2. 擾動處理(哈希值優化):對原始哈希值進行二次處理,讓高位參與運算,減少碰撞概率。
    JDK 1.8 中的實現:

    static final int hash(Object key) {int h;// 若 key 為 null,哈希值為 0;否則,將 hashCode 的高 16 位與低 16 位異或return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    
    ?

    作用:將高位信息融入低位,避免因數組長度較小時,高位無法參與索引計算導致的分布不均。

  3. 計算數組索引:用處理后的哈希值與「數組長度 - 1」進行「與運算」:

    index = (n - 1) & hash;  // n 為數組容量(2的冪次方)
    
    ?

    由于 n 是 2 的冪次方,n - 1?的二進制為「全 1」(如 15 是 1111),與運算等價于「取模運算」,但效率更高。

四、哈希沖突的解決

哈希沖突指不同 key 經過計算得到相同的數組索引。HashMap 采用鏈地址法(拉鏈法)?解決:

  • 當沖突發生時,新節點會被添加到該索引位置的鏈表尾部(JDK 1.8 后)。
  • 若鏈表長度超過閾值(默認 8)且數組長度 ≥ 64,鏈表轉為紅黑樹;若數組長度 < 64,則先觸發擴容(而非轉樹),避免數組較小時頻繁樹化。

五、擴容機制

當 HashMap 中的元素數量(size)超過「閾值(threshold)」時,會觸發擴容(resize),以減少哈希沖突。

  1. 閾值計算threshold = 容量(n) × 負載因子(loadFactor)

    • 負載因子默認 0.75(JDK 設計的平衡值:既避免空間浪費,又減少沖突)。
    • 例:初始容量 16,閾值 = 16 × 0.75 = 12,當元素數 > 12 時觸發擴容。
  2. 擴容過程

    • 新容量 = 原容量 × 2(始終保持 2 的冪次方)。
    • 重新計算閾值(新容量 × 負載因子)。
    • 重建哈希表:將原數組中的所有節點重新計算索引,遷移到新數組中(此過程稱為 rehash)。
    • JDK 1.8 優化:rehash 時,節點新索引要么是原索引,要么是原索引 + 原容量(無需重新計算哈希值,僅通過判斷高位即可),減少計算開銷。

六、關鍵特性與注意事項

  1. 無序性:節點存儲位置由哈希值決定,遍歷順序與插入順序無關(如需有序,可使用?LinkedHashMap)。
  2. 線程不安全:多線程環境下可能出現死循環(擴容時)或數據不一致,需使用?ConcurrentHashMap?替代。
  3. key 特性
    • 允許 key 為 null(僅允許一個,索引固定為 0)。
    • key 需重寫?hashCode()?和?equals()?方法(否則可能導致無法正確查詢、刪除元素)。
  4. 性能影響因素:容量、負載因子、哈希函數的優劣直接影響沖突率,進而影響性能。

七、key 的 hashCode () 和 equals () 規范

HashMap 對 key 的兩個方法有嚴格要求,否則會導致數據異常(如無法查詢到已插入的元素):

  1. equals () 相等的對象,hashCode () 必須相等
    若?a.equals(b) == true,則?a.hashCode() == b.hashCode()?必須成立。否則會導致兩個相等的 key 被映射到不同索引,無法正確查詢。

  2. hashCode () 相等的對象,equals () 可以不相等
    這會導致哈希沖突,此時通過 equals () 區分節點(遍歷鏈表 / 紅黑樹時,需用 equals () 比較 key 是否真正相等)。

  3. 最佳實踐
    重寫 hashCode () 時,應結合對象的關鍵屬性,且保證:

    • 屬性不變時,hashCode () 返回值不變。
    • 盡量讓不同對象的 hashCode () 分布均勻(減少沖突)。

總結

????????HashMap 是「數組 + 鏈表 + 紅黑樹」的復合結構,通過哈希函數定位元素,鏈地址法解決沖突,擴容機制平衡空間與性能,最終實現高效的 key-value 存儲與訪問。其設計體現了時間復雜度與空間復雜度的權衡,是 Java 中最常用的集合類之一。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/922349.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/922349.shtml
英文地址,請注明出處:http://en.pswp.cn/news/922349.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

關于電腦連接不到5g的WiFi時的一些解決辦法

方法一、設備管理器重卸載驅動后&#xff0c;重裝驅動。方法二、打開控制面板 “控制面板\網絡和 Internet\網絡連接” &#xff08;親測有效&#xff09;點擊更改適配器配置右擊當前的WLAN屬性點擊配置選擇“高級” 802.11a/b/g 無線模式選項欄 值&#xff1a;6.的雙…

Mathtype公式批量編號一鍵設置公式居中編號右對齊

插件[ygtools] 批量編號一鍵設置公式居中編號右對齊 單欄/多欄均可https://wwon.lanzout.com/i0NRf35vyw8j 下載密碼8543

基于ssm的小橘子出行客戶體驗評價系統[SSM]-計算機畢業設計源碼+LW文檔

摘要&#xff1a;隨著出行行業的快速發展&#xff0c;客戶體驗評價對于出行服務質量的提升至關重要。本文設計并實現了基于SSM&#xff08;Spring Spring MVC MyBatis&#xff09;框架的小橘子出行客戶體驗評價系統。該系統涵蓋系統用戶管理、司機信息管理、客戶評價管理等功…

算法日記---二分查找

目錄 前言 一、二分查找 1.思想 2.簡單二分 3.優點 4.局限性 二、模板 1.基本模板 2.簡單例題&#xff08;LeetCode&#xff09; 4.有重復元素的二分 5.0-1問題 總結 前言 本文通過講解簡單的二分查找配合leetcode例題對二分查找本質、模板進行了基礎的總結 提示&a…

Level Set(水平集)算法——形象化講解

目錄 維度一&#xff1a;核心思想與比喻&#xff08;它像什么&#xff1f;&#xff09; 維度二&#xff1a;要解決什么問題&#xff1f;&#xff08;它能干嘛&#xff1f;有什么用&#xff1f;&#xff09; 維度三&#xff1a;工作原理&#xff08;它是怎么做到的&#xff1…

DDoS 攻防“軍備競賽”的幕后

談到 DDoS&#xff08;分布式拒絕服務攻擊&#xff09;&#xff0c;很多人會想到“黑客租用肉雞發流量&#xff0c;網站直接崩”。但事實上&#xff0c;如今的 DDoS 攻防早已變成一場 軍備競賽。攻擊者的武器越來越“工業化”&#xff1a;僵尸網絡商品化&#xff1a;黑市上&…

如何用 Rust 重寫 SQLite 數據庫(二):是否有市場空間?

用 Rust 實現一個類似 SQLite 的嵌入式數據庫非常有意義&#xff0c;但需要結合具體目標和場景來評估其價值。以下從技術、生態、市場需求和個人成長等多個維度展開分析&#xff0c;并給出結論。一、技術價值&#xff1a;Rust 與數據庫的天然契合 SQLite 作為全球裝機量最大的數…

【Web】ImaginaryCTF 2025 wp

目錄 imaginary-notes certificate codenames-1 passwordless pearl imaginary-notes I made a new note taking app using Supabase! Its so secure, I put my flag as the password to the "admin" account. I even put my anonymous key somewhere in the si…

oracel如何找到外鍵子表

要找到導致外鍵約束沖突的子表&#xff08;即包含"child record"的表&#xff09;&#xff0c;可以通過以下SQL查詢在Oracle數據庫中定位&#xff1a;1. 查詢約束基本信息&#xff08;確定父表和子表&#xff09;SELECT owner, constraint_name, table_name AS child…

智源研究院新研究:突破物理世界智能邊界的RoboBrain 2.0,將重構具身AI能力天花板

當你對著家用機器人說"把杯子放在筆筒和鍵盤之間&#xff0c;對齊杯身logo"時&#xff0c;它能精準理解空間關系并執行動作&#xff1b;當多臺機器人在超市協作補貨時&#xff0c;它們能自主規劃軌跡、避免沖突并完成長周期任務——這些曾經出現在科幻電影中的場景&a…

【2025】Office核心組件Microsoft word,Excel,PowerPoint詳細使用指南

Office 核心組件使用指南 Microsoft Word 文字處理 Word主要用于創建和編輯文檔&#xff0c;如信件、報告、論文等。 2025Office&#x1f517; 1. 界面認識 快速訪問工具欄&#xff1a;位于左上角&#xff0c;可自定義保存、撤銷、恢復等常用命令。功能區&#xff1a;頂部…

【模型訓練篇】VeRL的使用 - RL(PPO)與源碼

繼續學習字節家的VeRL&#xff0c;今天來看看VeRL的RL&#xff0c;是VeRL系列的第三篇文章&#xff08;話說近期好多大事兒&#xff0c;我司發布了Longcat、韓立結嬰、阿里周五發布了QWen-Next都是好東西啊&#xff0c;學不過來了damn&#xff09; 底層分布式能力基礎Ray&…

QML Charts組件之折線圖的鼠標交互

目錄前言相關系列代碼示例詳解&#xff08;LineSeriesDemo3.qml&#xff09;功能概覽運行效果代碼說明工程下載參考前言 接上文&#xff08;QML Charts組件之折線圖的基礎屬性&#xff09;&#xff0c;本文將重點介紹LineSeries的鼠標交互&#xff0c;包括&#xff1a;鼠標拖拽…

二值信號量——學習筆記12

本文是筆者在學習 正點原子官方 的《【正點原子】手把手教你學FreeRTOS實時系統》系列視頻時整理的筆記。 視頻講解清晰透徹&#xff0c;非常感謝UP主的無私奉獻&#xff01;原課程鏈接如下&#xff1a; &#x1f449; B站視頻鏈接&#xff1a;??????【正點原子】手把手教…

裸機開發 時鐘配置,EPIT

1.概念時鐘(clock)&#xff1a;在電子系統中是一個產生穩定、周期性振蕩信號的電路或組件。這個信號像節拍器或心跳一樣&#xff0c;為數字電路中的各種操作提供同步時序基準。PLL&#xff08;phase locked loop&#xff09;鎖相環電路: 倍頻PFD&#xff08;phase fractional P…

Linux-文本三劍客(grep、sed、awk)

Linux-文本三劍客前言一、grep二、sed三、awk模式 -- 正則表達式關系表達式、運算符表達模式匹配表達式動作 輸出流程控制參數傳遞&#xff0c;awk接受外部變量統計數組的使用分組統計練習常用內置函數前言 grep、sed、awk 被稱為 “文本三劍客”&#xff0c;它們是處理文本文…

主流反爬蟲、反作弊防護與風控對抗手段

文章目錄1. 寫在前面2. 指紋檢測3. 行為驗證3. 加固防護4. 鏈路檢測5. 風控埋點6. 游客注冊7. 數據防護8. 賬號權重9. 反調阻斷【&#x1f3e0;作者主頁】&#xff1a;吳秋霖 【&#x1f4bc;作者介紹】&#xff1a;擅長爬蟲與JS加密逆向分析&#xff01;Python領域優質創作者、…

金蝶云星空插件開發記錄(一)

實現目的&#xff1a;新增供應商保存后&#xff0c;觸發釘釘審批流程&#xff0c;并根據釘釘審批結果回寫是否合格供應商。實現思路&#xff1a;通過BOS平臺供在應商管理界面新增兩個復選框字段&#xff1a;是否釘釘審批、是否合格供應商&#xff0c;若在新建供應商檔案時勾選是…

企業跨區域組網新解:SD-WAN技術打造安全穩定網絡體系

前言在數字化浪潮席卷全球的今天&#xff0c;企業跨區域網絡互聯已成為支撐業務發展的關鍵基礎設施。傳統MPLS專線雖性能穩定&#xff0c;但高昂成本和漫長部署周期令眾多企業望而卻步。SD-WAN技術的出現&#xff0c;正以其智能、靈活和成本效益的優勢&#xff0c;重塑企業組網…

Docker 容器化

引言在解釋docker是什么之前&#xff0c;我們首先應該先了解的是容器化的概念。什么是容器&#xff1f;就是一個沙箱&#xff0c;在這個沙箱中涵蓋了特定應用運行的一切依賴的內容。但他不是一個操作系統&#xff0c;且和底層的操作系統是隔離的。什么是容器化&#xff1f;容器…