HashMap底層原理

2022-09-12 01:36:16 字數 3286 閱讀 3802

陣列:其實所謂的陣列指的就是一組相關型別的變數集合,並且這些變數彼此之間沒有任何的關聯。儲存區間連續,占用記憶體嚴重,陣列有下標,查詢資料快,但是增刪比較慢;

雜湊表:hash table 既滿足了資料的快速查詢(根據關鍵碼值key value 而直接進行訪問的資料結構),也不會占用太多的記憶體空間,十分方便。雜湊表是陣列加鍊表組成。

hashmap結構及原理

hashmap是基於雜湊表的map介面的非同步實現。實現hashmap對資料的操作,允許有乙個null鍵,多個null值。

hashmap底層就是乙個陣列結構,陣列中的每一項又是乙個鍊錶。陣列+鍊錶結構,新建乙個hashmap的時候,就會初始化乙個陣列。entry就是陣列中的元素,每個entry其實就是乙個key-value的鍵值對,它持有乙個指向下乙個元素的引用,這就構成了鍊錶,hashmap底層將key-value當成乙個整體來處理,這個整體就是乙個entry物件。hashmap底層採用乙個entry【】陣列來儲存所有的key-value鍵值對,當需要儲存乙個entry物件時,會根據hash演算法來決定在其陣列中的位置,在根據equals方法決定其在該陣列位置上的鍊錶中的儲存位置;當需要取出乙個entry物件時,也會根據hash演算法找到其在陣列中的儲存位置, 在根據equals方法從該位置上的鍊錶中取出entry;

hashmap的儲存

put:(key-value)方法是hashmap中最重要的方法,使用hashmap最主要使用的就是put,get兩個方法。

判斷鍵值對陣列table[i]是否為空或者為null,否則執行resize()進行擴容;

根據鍵值key計算hash值得到插入的陣列索引  i  ,如果table[i] == null ,直接新建節點新增即可,轉入6,如果table[i] 不為空,則轉向3;

判斷table[i] 的首個元素是否和key一樣,如果相同(hashcode和equals)直接覆蓋value,否則轉向4;

判斷table[i] 是否為treenode,即table[i]是否為紅黑樹,如果是紅黑樹,則直接插入鍵值對,否則轉向5;

遍歷table[i] ,判斷鍊錶長度是否大於8,大於8的話把鍊錶轉換成紅黑樹,進行插入操作,否則進行鍊錶插入操作;便利時遇到相同key直接覆蓋value;

插入成功後,判斷實際存在的鍵值對數量size是否超過了threshold,如果超過,則擴容;

看一下put原始碼

get方法取值過程:

int  hash = key.hashcode();

int index =  hash%entry.length;

指定key通過hash函式得到key的hash值;

呼叫內部方法getnode(),得到桶號(一般為hash值對桶數求摸);

比較桶的內部元素是否和key相等,如不相等,則沒有找到,相等,則取出相等記錄的value;

如果得到key所在桶的頭結點恰好是紅黑樹節點,就呼叫紅黑樹節點的gettreenode()方法,否則就遍歷鍊錶節點。gettreenode()方法通過呼叫樹形節點的find()方法進行查詢。由於之前新增時已經保證這個樹是有序的,因此查詢時基本就是折半查詢,效率高;

如果對比節點的雜湊值和要查詢的雜湊值相等,就會判斷key是否相等,相等就直接返回;不相等就從子樹中遞迴查詢;

hashmap中直接位址用hash函式生成,衝突用比較函式解決。如果每個桶內部只有乙個元素,那麼查詢的時候只有一次比較。當許多桶內沒有值得時候,許多查詢就會更快

addentry方法

新增新元素前,判斷是否需要對map的陣列進行擴容,如果需要擴容,則擴容多大?

對於新增key-value鍵值對,如果可以的hash值相同,則構造單向列表;

原始碼分析:

該方法主要完成兩個功能,乙個是新增新的key到entry陣列中,第二個就是對於不同的key的hash值相同的情況下,在同乙個陣列下標出,構建單向鍊錶進行儲存;

原始碼如下:

hashmap碰撞以及解決方法(開放定址法,在雜湊法,鏈位址法,建立乙個公共溢位區)

當兩個物件的hashcode相同時,他們的bucket位置相同,hash碰撞就會發生。因為hashmap使用linkedlist儲存物件,這個entry(儲存鍵值對的map.entry物件)會儲存在linkedlist中。這兩個物件算hashcode相同,但是他們可能並不相等。那麼如何獲取這兩個物件的值呢?當我們呼叫get()方法,hashmap會使用鍵值物件的hashcode找到bucket位置,遍歷linkedlist一直找到值物件。找到bucket位置以後,會呼叫keys.equals()方法去找到linkedlist中正確的節點,最終找到要找的值物件,使用final修飾,並採用合適的equals()和hashcode()方法,減少碰撞。

hashmap擴容機制

擴容必須滿足兩個條件

hashmap在新增值的時候,它預設能儲存16個鍵值對,直到你使用這個hashmap時,它才會給hashmap分配16個鍵值對的儲存空間,(負載因子為0.75,閾值為12),當16個鍵值對已經儲存滿了,我們在新增第17個鍵值對的時候才會發生擴容現象,因為前16個值,每個值在底層陣列中分別佔據乙個位置,並沒有發生hash碰撞。

hashmap也有可能儲存更多的鍵值對,最多可以儲存26個鍵值對,我們來算一下:儲存的前11個值全部發生hash碰撞,存到陣列的同乙個位置中,(這時元素個數小於閾值12,不會擴容),之後存入15個值全部分散到陣列剩下的15個位置中,(這時元素個數大於等於閾值,但是每次存入元素並沒有發生hash碰撞,不會擴容),11+15=26,當我們存入第27個值得時候滿足以上兩個條件,hashmap才會發生擴容;

HashMap底層原理

1.hashmap概述 hashmap是基於雜湊表的map介面的非同步實現。此實現提供所有可選的對映操作,並允許使用null值和null鍵。此類不保證對映的順序,特別是它不保證該順序恆久不變。2.hashmap的資料結構 注意,迭代器的快速失敗行為不能得到保證,一般來說,存在非同步的併發修改時,不可...

HashMap底層原理

hashmap實現map介面,非執行緒安全的,區別於concurrenthashmap。允許使用null值和null鍵,不保證對映的順序.底層資料結構是乙個 陣列 鍊錶 紅黑樹 put 根據key計算得到key.hash h k.hashcode h 16 根據key.hash計算得到桶陣列的索引i...

HashMap底層原理

預設負載因子 static final float default load factor 0.75f 無參構造 public hashmap 有參構造 public hashmap int initialcapacity public hashmap int initialcapacity,flo...