HashMap 底層實現原理是什麼?

2022-07-06 21:06:12 字數 3006 閱讀 4627

陣列特點

儲存區間是連續,且占用記憶體嚴重,空間複雜也很大,時間複雜為o(1)。

優點:是隨機讀取效率很高,原因陣列是連續(隨機訪問性強,查詢速度快)。

缺點:插入和刪除資料效率低,因插入資料,這個位置後面的資料在記憶體中要往後移的,且大小固定不易動態擴充套件。

鍊錶特點

區間離散,占用記憶體寬鬆,空間複雜度小,時間複雜度o(n)。

優點:插入刪除速度快,記憶體利用率高,沒有大小固定,擴充套件靈活。

缺點:不能隨機查詢,每次都是從第乙個開始遍歷(查詢效率低)。

雜湊表特點

以上陣列和鍊錶,大家都知道各自優缺點。那麼我們能不能把以上兩種結合一起使用,從而實現查詢效率高和插入刪除效率也高的資料結構呢?答案是可以滴,那就是雜湊表可以滿足,接下來我們一起複習hashmap中的put()和get()方法實現原理。

hashmap的put()和get()的實現

1、map.put(k,v)實現原理

第一步首先將k,v封裝到node物件當中(節點)。

第二步它的底層會呼叫k的hashcode()方法得出hash值。

第三步通過雜湊表函式/雜湊演算法,將hash值轉換成陣列的下標,下標位置上如果沒有任何元素,就把node新增到這個位置上。如果說下標對應的位置上有鍊錶。此時,就會拿著k和鍊錶上每個節點的k進行equal。如果所有的equals方法返回都是false,那麼這個新的節點將被新增到鍊錶的末尾。如其中有乙個equals返回了true,那麼這個節點的value將會被覆蓋。

2、map.get(k)實現原理

第一步:先呼叫k的hashcode()方法得出雜湊值,並通過雜湊演算法轉換成陣列的下標。

重點理解如果這個位置上什麼都沒有,則返回null。如果這個位置上有單向鍊錶,那麼它就會拿著引數k和單向鍊錶上的每乙個節點的k進行equals,如果所有equals方法都返回false,則get方法返回null。如果其中乙個節點的k和引數k進行equals返回true,那麼此時該節點的value就是我們要找的value了,get方法最終返回這個要找的value。

在 jdk 1.7 中 hashmap 是以陣列加鍊表的形式組成的,jdk 1.8 之後新增了紅黑樹的組成結構,當鍊表大於 8 並且雜湊桶的容量大於 64 時,鍊錶結構會轉換成紅黑樹結構,它的組成結構如下圖所示:

陣列中的元素我們稱之為雜湊桶

每個雜湊桶中包含了四個字段:hash、key、value、next,其中 next 表示鍊錶的下乙個節點。

jdk 1.8 之所以新增紅黑樹是因為一旦鍊錶過長,會嚴重影響 hashmap 的效能,而紅黑樹具有快速增刪改查的特點,這樣就可以有效的解決鍊錶過長時操作比較慢的問題。

hashmap 原始碼中三個重要方法:查詢、新增和資料擴容

為何隨機增刪、查詢效率都很高的原因是?

原因:增刪是在鍊錶上完成的,而查詢只需掃瞄部分,則效率高。

為什麼放在hashmap集合key部分的元素需要重寫equals方法?

因為equals預設比較是兩個物件記憶體位址

hashmap集合的key特點:

hashmap集合的key,會先後呼叫兩個方法,hashcode and equals方法,這兩個方法都需要重寫。

當雜湊衝突時我們需要通過判斷 key 值是否相等,才能確認此元素是不是我們想要的元素。

如果o1和o2的hash值相同,就會存放到同乙個單向鍊錶上,

如果不同,但由於雜湊演算法執行結束之後轉換的陣列下標可能相同,此時會發上「雜湊碰撞」。

jdk 1.8 在擴容時並沒有像 jdk 1.7 那樣,重新計算每個元素的雜湊值,而是通過高位運算(e.hash& oldcap)來確定元素是否需要移動

載入因子也叫擴容因子或負載因子,用來判斷什麼時候進行擴容的,假如載入因子是 0.5,hashmap 的初始化容量是 16,那麼當 hashmap 中有 16*0.5=8 個元素時,hashmap 就會進行擴容。

載入因子為什麼是 0.75 而不是 0.5 或者 1.0 呢?

這其實是出於容量和效能之間平衡的結果:

所以綜合了以上情況就取了乙個 0.5 到 1.0 的平均數 0.75 作為載入因子。

jdk8之後,如果雜湊表單向鍊錶中元素超過8個,那麼單向鍊錶這種資料結構會變成紅黑樹資料結構當紅黑樹上的節點數量小於6個,會重新把紅黑樹變成單向鍊錶資料結構。

無序,不可重複為什麼是無序的?因為不一定掛到哪乙個單向鍊錶上的,因此加入順序和取出也不一樣。

怎麼保持不可重複?使用equals方法來保證hashmap集合key不可重複,如key重複來,value就會覆蓋。

存放在hashmap集合key部分的元素,其實就是存放在hashset集合中,則hashset集合也需要重寫equals和hashcode方法

hashmap集合的預設初始化容量為16,預設載入因子為0.75,也就是說這個預設載入因子是當hashmap集合底層陣列的容量達到75%時,陣列就開始擴容。hashmap集合初始化容量是2的陪數,為了達到雜湊均勻,提高hashmap集合的訪問效率,

hashmap底層實現原理

每次初始化hashmap都會構造乙個table陣列,而table陣列的元素為entry節點。static class entryimplements map.entryhashmap也可以說是乙個陣列鍊錶,hashmap裡面有乙個非常重要的內部靜態類 entry,這個entry非常重要,它裡面包含了...

HashMap底層實現原理

hashmap map new hashmap 在例項化以後,底層建立了長度為16的一維陣列entry table 已經執行過put操作.map.put key1 value1 呼叫key1所在類的hashcode 計算key1雜湊值,此雜湊值經過某種演算法計算後,得到在entry陣列中的存放位置 ...

HashMap底層實現原理

一 jdk1.7中hashmap的底層實現原理 首先,當我們通過hashmap的構造方法建立乙個hashmap物件時,底層就會建立乙個entry型別的一維陣列 預設初始化長度為16 當我們執行put操作的時候,會呼叫key所屬類的hashcode方法計算出key的hash值,然後將hash值通過雜湊...