1. 程式人生 > >當我們建立HashMap時,底層到底做了什麼?

當我們建立HashMap時,底層到底做了什麼?

## jdk1.7中的底層實現過程(底層基於陣列+連結串列) 在我們new HashMap()時,底層建立了預設長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap裡新增資料的時候: 首先,呼叫key1所在類的hashCode()計算key1的雜湊值,通過key1的hash值與陣列的最大索引進行位運算以後,得到了在 Entry陣列中的存放位置: 如果此位置上的資料為空,此時的key1-value1新增成功。 如果此位置上的資料不為空(意味著此位置已經存在一個或多個數據),比較key1和已經存在的一個或多個數據的雜湊值: 如果key1的雜湊值與已經存在的資料的雜湊值都不相同,此時key1-value1新增成功。 如果key1的雜湊值與已經存在的資料的某一個數據的雜湊值相同,繼續比較:呼叫key1所在類的equals()方法: 如果equals()返回false,此時key1-value1新增成功; 如果equals()返回true,使用value1替換value2。 需要注意的是,若原來位置已有資料,則此時key1-value1和原來的資料以連結串列的方式儲存。 在不斷的新增過程中,會涉及到擴容問題,當陣列容量大於陣列現有長度乘以載入因子(如16*0.75,預設的載入因子為0.75)的時候,就會進行陣列擴容,以減少雜湊衝突(雜湊衝突是指雜湊函式算出來的地址被別的元素佔用了),提高查詢效率。預設的擴容方式,擴容為原來容量的2倍,並將原有的資料複製過來。 ![](https://img2020.cnblogs.com/blog/1942540/202006/1942540-20200627111454018-1216144925.png) ## jdk1.8的底層實現過程(底層基於陣列+連結串列+紅黑樹) jdk1.8與jdk1.7中底層的建立過程相似,但有不同,首先,new HashMap()底層沒有創建出一個長度為16的陣列,在呼叫put()方法時,判斷陣列是否存在,如果不存在建立長度為16的Node[ ]陣列。接下來的過程與jdk1.7相似。最後,當某一個索引位置上的元素以連結串列形式存在的資料個數>8且當前陣列的長度>64時,此時此索引位置上的所有資料改為使用紅黑樹儲存。 在jdk1.7中,即使在“陣列容量大於陣列現有長度乘以載入因子”時擴容,也不可避免地會有雜湊衝突存在,因此,在jdk1.8中引入紅黑樹是為了進一步減少雜湊衝突,提高查詢效率。 紅黑樹是一種自平衡的二叉查詢樹,是一種資料結構,典型的用途是實現關聯陣列。根節點必須是黑色,其他每個節點要麼是紅色,要麼是黑色。 **結論**:HashMap鍵是不能重複的,去除重複的條件是依賴鍵的hashCode方法和equals方法,如果鍵是自己的物件型別,必須要重寫hashCode方法和equals方法,否則,不能去除重複的鍵。 ![](https://img2020.cnblogs.com/blog/1942540/202006/1942540-20200627111428377-2425043