今天想了解點HashMap的存取解析。大家都知道HashMap是鍵值對存在的,key-value的形式。但,內部是怎麼存儲的?我們一起來看看吧
標注:基於的jdk版本為1.6.0_45
First,大家都知道Map的entrySet方法返回的是Set<Entry>,所以就好奇Entry到底是個什麼東西?
Entry是接口,是Map接口中的一個內部接口,Map提供的接口就不給大家介紹了,Entry提供的接口方法有:
K getKey() //獲取Entry的key值
V getValue() //獲取Entry的value值
setValue(V value) //替換value值
equals(Object o)//你懂的
hashCode() //你也懂的
其實這些方法大家也不陌生 微笑
Second,HashMap.Entry實現Map.Entry接口?
看代碼,我們發現HashMap.Entry是一個Link結構,並且key和value為其屬性,並使用next指向下一個Entry。
關於方法的實現就不介紹了,HashMap額外提供了兩個空方法,一個是recordAccess,一個是recordRemoval,在HashMap的介紹中,不多做介紹,在後面的LinkedHashMap再詳細說明
Third,HashMap怎麼利用Entry存放key-Value呢?並且,HashMap是怎麼遍歷的呢?是對Entry的Link遍歷?有了這一連串的疑問之後,繼續探索吧!
HashMap使用Entry數組,如下圖1:
上圖中transient修飾符是啥意思呢?
是一個臨時非序列化的變量,不可以被序列化存放起來。生命周期僅存於內存中。
Third_First:存放
HashMap提供的put方法執行操作,請注意putForNullKey和put的方法類似,只是putForNullKey定好了table的存放位置:
1.獲取key的hash。其中的hash方法只是為了保證它有唯一的值,並且null的hash一定是0.
2.在圖1中的table中找到key對應的位置使用的方式 hash & length,確定index
3.在table[i]存放的Entry對象中繼續遍歷,看其中是否存在hash、key是否完全一樣的,如果是則直接替換
4.如果步驟3找不到完全匹配的,則直接在table[i]對應的地方最後一個鏈表節點增加該元素
addEntry的處理:1.取到index的Entry;2.重新給一個新的鏈接,鏈接的是最新放入的,完全符合隊列link;3.長度超過設定擴展至兩倍
Third_Second:遍歷
其中用內部類HashIterator處理的,設定一個next Entry和current Entry。next為下一個點,current是當前點。咱們使用的Iterator.next接口具體實現方法為HashIterator的nextEntry。nextEntry方法中1.是對Entry鏈進行遍歷,如果到這個鏈的隊尾,則從table中取得下一個Entry鏈。2.將之前查找到的Entry返回給前台。源碼如下:
一位姓丁的NB同事曾經排查過一個高並發的情況下:HashMap如果EntryA的next指向EntryB,而EntryB的next指向EntryA,會導致get死循環。