BAT面試必問HashMap原始碼分析
HashMap 簡介
HashMap 主要用來存放鍵值對,它基於雜湊表的Map介面實現,是常用的Java集合之一。
JDK1.8 之前 HashMap 由 陣列+連結串列 組成的,陣列是 HashMap 的主體,連結串列則是主要為了解決雜湊衝突而存在的(“拉鍊法”解決衝突).JDK1.8 以後在解決雜湊衝突時有了較大的變化,當連結串列長度大於閾值(預設為 8)時,將連結串列轉化為紅黑樹,以減少搜尋時間。
底層資料結構分析
JDK1.8之前
JDK1.8 之前 HashMap 底層是
陣列和連結串列
結合在一起使用也就是
連結串列雜湊
。
HashMap 透過 key 的 hashCode 經過擾動函式處理過後得到 hash 值,然後透過
(n - 1) & hash
判斷當前元素存放的位置(這裡的 n 指的是陣列的長度),如果當前位置存在元素的話,就判斷該元素與要存入的元素的 hash 值以及 key 是否相同,如果相同的話,直接覆蓋,不相同就透過拉鍊法解決衝突。
所謂擾動函式指的就是 HashMap 的 hash 方法。使用 hash 方法也就是擾動函式是為了防止一些實現比較差的 hashCode() 方法 換句話說使用擾動函式之後可以減少碰撞。
JDK 1.8 HashMap 的 hash 方法原始碼:
JDK 1.8 的 hash方法 相比於 JDK 1.7 hash 方法更加簡化,但是原理不變。
1 2 3 4 5 6 7 |
|
對比一下 JDK1.7的 HashMap 的 hash 方法原始碼.
1 2 3 4 5 6 7 8 |
|
相比於 JDK1.8 的 hash 方法 ,JDK 1.7 的 hash 方法的效能會稍差一點點,因為畢竟擾動了 4 次。
所謂 “拉鍊法” 就是:將連結串列和陣列相結合。也就是說建立一個連結串列陣列,陣列中每一格就是一個連結串列。若遇到雜湊衝突,則將衝突的值加到連結串列中即可。
JDK1.8之後
相比於之前的版本,jdk1.8在解決雜湊衝突時有了較大的變化,當連結串列長度大於閾值(預設為8)時,將連結串列轉化為紅黑樹,以減少搜尋時間。
類的屬性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
- loadFactor載入因子
loadFactor載入因子是控制陣列存放資料的疏密程度,loadFactor越趨近於1,那麼 陣列中存放的資料(entry)也就越多,也就越密,也就是會讓連結串列的長度增加,load Factor越小,也就是趨近於0,
loadFactor太大導致查詢元素效率低,太小導致陣列的利用率低,存放的資料會很分散。loadFactor的預設值為0.75f是官方給出的一個比較好的臨界值。
- threshold
threshold = capacity * loadFactor,當Size>=threshold的時候,那麼就要考慮對陣列的擴增了,也就是說,這個的意思就是 衡量陣列是否需要擴增的一個標準。
Node節點類原始碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
樹節點類原始碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
HashMap原始碼分析
構造方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
putMapEntries方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
put方法
HashMap只提供了put用於新增元素,putVal方法只是給put方法呼叫的一個方法,並沒有提供給使用者使用。
對putVal方法新增元素的分析如下:
- ①如果定位到的陣列位置沒有元素 就直接插入。
-
②如果定位到的陣列位置有元素就和要插入的 key 比較,如果key相同就直接覆蓋,如果 key 不相同,就判斷 p 是否是一個樹節點,如果是就呼叫
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value)
將元素新增進入。如果不是就遍歷連結串列插入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
|
我們再來對比一下 JDK1.7 put方法的程式碼
對於put方法的分析如下:
- ①如果定位到的陣列位置沒有元素 就直接插入。
- ②如果定位到的陣列位置有元素,遍歷以這個元素為頭結點的連結串列,依次和插入的key比較,如果key相同就直接覆蓋,不同就採用頭插法插入元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
get方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
resize方法
進行擴容,會伴隨著一次重新hash分配,並且會遍歷hash表中所有的元素,是非常耗時的。在編寫程式中,要儘量避免resize。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
|
HashMap常用方法測試
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
|
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69912582/viewspace-2645000/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- hashmap原始碼面試分析HashMap原始碼面試
- Java1.7的HashMap原始碼分析-面試必備技能JavaHashMap原始碼面試
- 面試必問:HashMap 底層實現原理分析面試HashMap
- HashMap:從原始碼分析到面試題HashMap原始碼面試題
- 面試必備:HashMap原始碼解析(JDK8)面試HashMap原始碼JDK
- Java 進階必備:HashMap 原始碼分析JavaHashMap原始碼
- HashMap原始碼分析 —— 一篇文章搞定HashMap面試HashMap原始碼面試
- 原始碼分析——HashMap原始碼HashMap
- HashMap原始碼分析HashMap原始碼
- HashMap 原始碼分析HashMap原始碼
- 原始碼分析之 HashMap原始碼HashMap
- Java:HashMap原始碼分析JavaHashMap原始碼
- 原始碼|jdk原始碼之HashMap分析(一)原始碼JDKHashMap
- 原始碼|jdk原始碼之HashMap分析(二)原始碼JDKHashMap
- HashMap原始碼實現分析HashMap原始碼
- JDK 1.6 HashMap 原始碼分析JDKHashMap原始碼
- HashMap-put原始碼分析HashMap原始碼
- HashMap原始碼分析(JDK 1.8)HashMap原始碼JDK
- jdk原始碼分析之HashMapJDK原始碼HashMap
- 死磕 jdk原始碼之HashMap原始碼分析JDK原始碼HashMap
- JDK1.8 hashMap原始碼分析JDKHashMap原始碼
- HashMap原始碼分析 JDK1.8HashMap原始碼JDK
- java基礎:HashMap — 原始碼分析JavaHashMap原始碼
- HashMap原始碼分析,未完待續HashMap原始碼
- java集合原始碼分析(六):HashMapJava原始碼HashMap
- Java基礎——HashMap原始碼分析JavaHashMap原始碼
- HashMap原始碼分析(JDK8)HashMap原始碼JDK
- Java HashMap例項原始碼分析JavaHashMap原始碼
- HashMap原始碼分析(二):看完徹底瞭解HashMapHashMap原始碼
- 原始碼分析系列1:HashMap原始碼分析(基於JDK1.8)原始碼HashMapJDK
- HashMap擴容機制原始碼分析HashMap原始碼
- HashMap從認識到原始碼分析HashMap原始碼
- JDK1.8原始碼分析之HashMapJDK原始碼HashMap
- HashMap 實現原理與原始碼分析HashMap原始碼
- HashMap實現原理及原始碼分析HashMap原始碼
- Java類集框架 —— HashMap原始碼分析Java框架HashMap原始碼
- jdk1.8原始碼之HashMap分析JDK原始碼HashMap
- 面試必會之ArrayList原始碼分析以及手寫ArrayList面試原始碼