HashMap1.7
Jdk1.7的HashMap實質上是一個Entry數組,數組的每一個元素是一個單向鏈表,其數據結構以下:數組
HashMap的put方法:安全
- 判斷map中的數組是不是空的,是則初始化數組。(可見HashMap在構造函數的時候其實啥都沒幹,真正初始化數組的時候是在put方法執行的)
- 判斷key值是否爲null,爲null則將值放入在數組的第一個元素即table[0]
- 根據key計算出hash值
- 經過hash值從table數組找到對應的下表
- 取數組table對應下標的鏈表並遍歷判斷是否存在相同key值,存在則覆蓋舊值並返回
- key值不存在則將Entry添加到鏈表中
仔細看看addEntry方法的實現,主要流程以下:數據結構
- 首先判斷當前size是否已經達到了閾值且對應數組小標已經有值則須要擴容,擴容必定是數組大小的2倍,擴容後從新計算元素在新數組裏的下表
- 在數組對應下表添加新的原色(新添加元素必定是添加都鏈表的表頭,將next指向舊值)
HashMap的get方法函數
- 判斷key值是否爲空,爲空直接從數據的第一個元素返回值
- 根據key計算出hash,根據hash找到對應數組下表,而後在根據hash從對應鏈表中取值便可
HashMap存在的非線程安全的問題:線程
- 擴容時候造成環形鏈表
- 添加數據時數據丟失
HashMap1.8
HashMap1.8相比1.7有比較大的改進,數據結構由1.7的數組+鏈表修改成數組+鏈表+紅黑樹,其中當鏈表的元素大於等於8的時候會轉換成紅黑樹存儲,另外就是擴容的時間點,1.7是先擴容再添加元素,1.8是先添加元素後再擴容。其數據結構由1.7的Entry數組變爲Node數組,如: blog
put方法主要代碼以下: get
get方法,相對比較簡單:hash
- 經過key計算出hash值,而後找到對應數組的下表 2.判斷對應下表的第一個值是否就是要找的對應key值,如果,直接返回,不然進行第3步
- 判斷元素是鏈表仍是紅黑樹,而後相應的獲取對應的值。
總結:table
- 兩個版本採用的存儲結構不一樣,一個是數組+鏈表,一個是數組+鏈表+紅黑樹
- 擴容順序不一樣,1.7是先擴容再插入,1.8是先插入在擴容
- 1.8中鏈表轉紅黑樹的條件是鏈表長度大於等於8 4.均不是線程安全
- 待補充