當咱們建立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添加成功。blog

若是key1的哈希值與已經存在的數據的某一個數據的哈希值相同,繼續比較:調用key1所在類的equals()方法:索引

若是equals()返回false,此時key1-value1添加成功;hash

若是equals()返回true,使用value1替換value2。table

須要注意的是,若原來位置已有數據,則此時key1-value1和原來的數據以鏈表的方式存儲。效率

在不斷的添加過程當中,會涉及到擴容問題,當數組容量大於數組現有長度乘以加載因子(如16*0.75,默認的加載因子爲0.75)的時候,就會進行數組擴容,以減小哈希衝突(哈希衝突是指哈希函數算出來的地址被別的元素佔用了),提升查詢效率。默認的擴容方式,擴容爲原來容量的2倍,並將原有的數據複製過來。
jdk

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方法,不然,不能去除重複的鍵。

相關文章
相關標籤/搜索