深入解析Java 8中HashMap的底層原理

引言

HashMap是Java中常用的集合類,用于存儲鍵值對。其底層實現經過多次優化,包括哈希算法、數組擴容、鏈表轉紅黑樹等。本文將深入研究HashMap的底層原理,并詳細探討如何解決哈希碰撞的技術。

1. 哈希算法

HashMap的核心是哈希算法,它通過將鍵的哈希碼映射到數組索引,實現快速的數據查找和插入。在JDK 1.8中,哈希算法經過了一些優化,以提高均勻性和減少碰撞的可能性。

2. 數組與鏈表結構

HashMap的底層數據結構是一個數組,每個數組元素是一個鏈表(或紅黑樹)。當多個鍵映射到相同的索引位置時,它們將被存儲在同一個鏈表中。為了解決哈希碰撞,鏈表中存儲的是一個個鍵值對。

3. 鍵值對的存儲

HashMap中,鍵值對以Node對象的形式存儲。每個Node包含鍵、值、哈希碼以及指向下一個Node的引用。當產生哈希沖突時,新的Node將被添加到鏈表的末尾。

4. 解決哈希碰撞的方法

  1. 鏈地址法:當發生哈希沖突時,將沖突的元素以鏈表的形式鏈接在一起,同一個鏈表上的元素哈希值相同。
    在這里插入圖片描述

  2. 紅黑樹:當鏈表長度超過一定閾值(默認為8)時,鏈表會轉換為紅黑樹,可以減少查找時間。因為紅黑樹的時間復雜度為O(logn),而鏈表為O(n)。

  3. 擴容rehash:當HashMap中的元素數量太多,超過數組大小*加載因子時,會發生擴容。擴容后,需要對原數組中的所有元素重新計算哈希值,然后放到新的擴容后的數組中,這樣可以增加鏈表長度,減少哈希沖突。

  4. 優化哈希算法:JDK 1.8中優化了哈希算法,通過hashCode()的高16位異或低16位實現的:(h = k.hashCode()) ^ (h >>> 16),提高了哈希碰撞分布性。

所以Java 8中HashMap主要通過鏈地址法+紅黑樹+擴容rehash+優化哈希算法來解決哈希沖突。這些方法相結合可以有效地解決哈希沖突問題,提高HashMap的性能。

5. 數組擴容機制

HashMap中的元素數量超過容量乘以加載因子時,數組會被擴容。在JDK 1.8中,默認加載因子是0.75。擴容涉及到重新計算哈希碼、重新分配數組,并將現有元素重新放置到新的數組中。這確保了HashMap的性能和空間的平衡。

6. 紅黑樹的引入

為了應對鏈表過長的情況,JDK 1.8引入了紅黑樹。當鏈表長度達到8時,鏈表將被轉換為紅黑樹,以提高查找效率。紅黑樹的引入使得在最壞情況下,查找時間復雜度從O(n)降低到O(log n)。

為什么當鏈表長度達到8時,鏈表將被轉換為紅黑樹,又為什么紅黑樹轉鏈表的閾值為6?
首先和hashcode碰撞次數的泊松分布有關,主要是為了實現時間和空間的平衡,在負載因子為0.75默認情況下,單個hash槽內元素個數為8的概率小于百萬分之一,將7作為一個分水嶺,等于7時不做轉換,大于等于8才轉紅黑樹,小于等于6才轉鏈表,鏈表中元素個數為8時的概率已經非常小,再多的就更少了,所以原作者在選擇鏈表元素個數時選擇了8,是根據概率統計而選擇的,紅黑樹中的TreeNode,是鏈表中的Node所占空間的2倍,雖然紅黑樹的查找效率為o(logN),要優于鏈表的o(N),但是當鏈表長度比較小的時候,即使全部遍歷,時間復雜度也不會太高,所以,要尋找一種時間和空間的平衡,即在鏈表長度達到一個閾值,之后再轉換為紅黑樹,之所以是8,是因為Java的源碼貢獻者,在進行大量實驗發現,hash碰撞發生8次的概率,已經降低到了0.00000006,幾乎為不可能事件,如果真的碰撞發生了8次,那么這個時候說明由于元素,本身和hash函數的原因,此次操作的hash碰撞的可能性非常大了,后序可能還會繼續發生hash碰撞,所以,這個時候,就應該將鏈表轉換為紅黑樹了,也就是為什么鏈表轉紅黑樹的閾值是8;
最后,紅黑樹轉鏈表的閾值為6,主要是因為:如果也將該閾值設置于8,那么當hash碰撞在8時,會反生鏈表和紅黑樹的不停相互激蕩轉換,白白浪費資源。

7. 在Java 8中的實現細節

在JDK 1.8中,HashMap的實現經過了優化,包括更好的哈希算法、紅黑樹的引入、鏈表長度的控制等。這些變化使得HashMap在面對各種情況時都能提供高效的性能。

8. 性能優化與注意事項

在使用HashMap時,需要注意一些性能優化的問題,例如合理選擇初始容量和加載因子、避免頻繁擴容等。對于特定的應用場景,可以通過調整這些參數來達到更好的性能。

結論

HashMap作為Java中常用的數據結構之一,在JDK 1.8中經過了一系列的優化和改進。深入理解其底層原理,包括哈希算法、數組與鏈表結構、紅黑樹的引入等,以及如何解決哈希碰撞的技術,有助于更好地使用和理解HashMap的性能特性。在實際應用中,根據具體場景選擇適當的參數,可以更好地發揮HashMap的優勢,提高程序的性能和效率。

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

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

相關文章

Day38:518.零錢兌換II、377. 組合總和 Ⅳ

文章目錄 518.零錢兌換II思路代碼實現 377. 組合總和 Ⅳ思路代碼實現 518.零錢兌換II 題目鏈接 思路 確定dp數組(dp table)以及下標的含義 dp[j]:組合元素和為j的組合方式確定遞推公式 題目不是選取最優解,而是求路徑總和&…

【運動規劃】191 自適應跟蹤kinodynamicrrt的路徑

分層法: two layer approach 自適應控制,跟隨軌跡。運動規劃:擴展自由空間(基于速度約束縮小自由空間)為控制部分留余量,確保安全。 控制設計: 考慮平移和旋轉,速度環控制&#xff…

銀河麒麟安裝Docker

# 配置阿里云 Centos8 鏡像源,需要額外的一些依賴,而這些依賴在麒麟官方的源里面是沒有的 sudo curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-8.repo# 配置阿里云 docker 鏡像源 sudo yum-config-manager --add-r…

【23真題】Top3!最高148分,數二英二!

今天分享的是23年西安交通大學815的信號與系統數字信號處理試題及解析。眾所周知,Top3一共有10所,其中就包括了西安交大! 本套試卷難度分析:平均分為117-128分,最高分為148分!22年西安交大909/815的真題我…

2022-4-11 南科大現代控制與最優估計

CLEAR_LAB B站視頻 矩陣的分塊矩陣操作 diagonal 對角陣 identity matrix 單位矩陣 矩陣克羅內克積

【LeetCode二叉樹進階題目】606. 根據二叉樹創建字符串,102. 二叉樹的層序遍歷,107. 二叉樹的層序遍歷 II

二叉樹進階題目 606. 根據二叉樹創建字符串解題思路及實現 102. 二叉樹的層序遍歷解題思路及實現 107. 二叉樹的層序遍歷 II解題思路及實現 606. 根據二叉樹創建字符串 描述 給你二叉樹的根節點 root ,請你采用前序遍歷的方式,將二叉樹轉化為一個由括號…

Android、ESP32、ESP8266的mqtt通信

Android activity_main <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-auto"xmlns:tools"http:/…

Python dbm庫:利用鍵值對存儲數據

更多Python學習內容&#xff1a;ipengtao.com 大家好&#xff0c;我是濤哥&#xff0c;今天為大家分享 Python dbm庫&#xff1a;利用鍵值對存儲數據&#xff0c;文章6000字&#xff0c;閱讀大約20分鐘&#xff0c;大家enjoy~~ Python中的dbm模塊提供了一種輕量級的數據庫管理工…

【ARM 嵌入式 編譯系列 2.3 -- GCC 中指定 ARMv8-M 的 Thumb 指令集參數詳細介紹】

請閱讀【ARM GCC 編譯專欄導讀】 上篇文章:【ARM 嵌入式 編譯系列 2.2 – 如何在Makefile 中添加編譯時間 | 編譯作者| 編譯 git id】 下篇文章:【ARM 嵌入式 C 入門及漸進 3 – GCC attribute((weak)) 弱符號使用】 文章目錄 ARMv8-M 架構Thumb 指令集ARMv8-M 與 Thumb-mth…

call ,apply,bind 及異同點

目錄 1、call 2、apply 3、bind 4、三者異同 1、call call 函數調用 &#xff1a;1、讓函數執行 2、改變函數this指向 參數&#xff1a; 第一個參數是this指 向&#xff0c;第二個參數開始傳遞給函數的實參 函數名.call&#xff08;this指…

redis---主從復制及哨兵模式(高可用)

主從復制 主從復制&#xff1a;主從復制是redis實現高可用的基礎&#xff0c;哨兵模式和集群都是在主從復制的基礎之上實現高可用。 主從負責的工作原理 1、主節點&#xff08;master&#xff09; 從節點&#xff08;slave&#xff09;組成&#xff0c;數據復制是單向的&a…

VUE+element可以為空不為空時只能為(正整數和0)的驗證

rule{ 變量: [ { required: true, validator: validateparamPosition, trigger: blur }] } ??????? ??????? ??????? var validateparamPosition (rule, value, callback) > { if (!value) { //先判斷空可以過 ca…

【HarmonyOS】JSON格式化解析Map數據失敗

【關鍵字】 數據轉換、JSON.stringify、Object.fromEntries 【問題背景】 將數組轉換成Map對象&#xff0c;然后調用let str JSON.stringify(newMap)&#xff0c;將Map轉換成字符串&#xff0c;轉換出來的結果是{} 問題代碼&#xff1a; let data [{ key: where, value: …

python數據結構與算法-13_高級排序算法-快速排序

快速排序 快速排序名字可不是蓋的&#xff0c;很多程序語言標準庫實現的內置排序都有它的身影&#xff0c;我們就直奔主題吧。 和歸并排序一樣&#xff0c;快排也是一種分而治之(divide and conquer)的策略。歸并排序把數組遞歸成只有單個元素的數組&#xff0c;之后再不斷兩兩…

docker安裝mysql掛著目錄和mysql備份和恢復

第一&#xff0c;鏡像拉取&#xff0c;運行鏡像并掛載目錄&#xff0c;嘗試掛bin下&#xff0c;啟動不了&#xff0c;不知為啥 docker run --privilegedtrue -itd --namevmysql -p 3306:3306 -v /home/vmysql:/home/vmysql -e MYSQL_ROOT_PASSWORD123456 mysql&#xff08;圖…

Nancy (二)

最近做CS項目&#xff0c;一直在使用TCPSocket 做數據傳輸&#xff0c;不太爽&#xff0c;砸門可是多年BS的開發&#xff0c;這樣開發接口出去比較費勁&#xff0c;但是又不想用asp.net mvc webapi,要按照IIS&#xff0c;有些工控機的系統環境也是很尷尬的&#xff0c;那么也可…

用好說 AI 玩轉奧特曼表情包,居然還能和他們聊個天

你喜歡奧特曼嗎&#xff1f;你相信光嗎&#xff1f; 如果你已經追完了特攝劇、刷完了大電影、用濫了那幾個表情包&#xff0c;那不如來試試用 AI 給自己整點活兒新 “物料”。 不管是和奧特曼 “面對面” 聊天還是 “無中生有” 表情包&#xff0c;AI 都能做&#xff01; (※…

Python 使用SQLAlchemy數據庫模塊

SQLAlchemy 是用Python編程語言開發的一個開源項目&#xff0c;它提供了SQL工具包和ORM對象關系映射工具&#xff0c;使用MIT許可證發行&#xff0c;SQLAlchemy 提供高效和高性能的數據庫訪問&#xff0c;實現了完整的企業級持久模型。 ORM&#xff08;對象關系映射&#xff0…

MySQL For Windows的下載與安裝

教程https://www.bilibili.com/read/cv26499785/ windowse下載地址https://dev.mysql.com/get/Downloads/MySQLInstaller/mysql-installer-community-8.0.35.0.msi

代理模式 (Proxy Pattern)

定義&#xff1a; 代理模式&#xff08;Proxy Pattern&#xff09;是一種結構型設計模式&#xff0c;它通過提供一個代理&#xff08;或稱代表&#xff09;對象來控制對另一個對象的訪問。這種模式創建了一個代理對象&#xff0c;用來代表實際對象的功能&#xff0c;從而可以在…