陣列+單向鍊錶+紅黑樹
陣列:陣列每一項都是乙個鍊錶,其實就是陣列和鍊錶的結合體
單向鍊錶:當法神hash碰撞時,首先會找到陣列對應位置,然後1.8採用尾插入法(1.7採用頭插入法),形成乙個單項鍊表結構
紅黑樹:當陣列中每項的鍊錶長度大於8時,會轉換為紅黑樹
hash碰撞:不同的key可能會產生相同的hash值;
方案:鍊錶發,再雜湊法;
hashmap中採用鍊錶發,在concurrenthashmap中採用雜湊法;
二叉查詢樹在特殊情況下也會變成線性結構,和原來鍊錶有共同的問題,節點太深,查詢效能慢;
紅黑樹相比二叉樹,在檢索的時候效率其實差不多,都是通過平衡來二分查詢。但對於插入刪除等操效率提高很多。紅黑樹不像二叉樹一樣追求絕對的平衡,它允許區域性很少的不完全平衡,這樣對於效率影響不大,但省去了很多沒有必要的調平衡操作,二叉樹調平衡有時候代價較大,所以二叉樹的效率不如紅黑樹;
使用紅黑樹主要用於提高查詢速度;
當資料較少的時候,採用鍊錶要比紅黑樹效率高,因為平衡二叉樹保持平衡需要耗費資源,那麼前期資料較少時採用鍊錶,當鍊表中的資料長度大於8時,就將鍊錶轉換成紅黑樹,可以加快資料的插敘速度,官方測試8為效能最優。
public v put(k key, v value)
計算key的hash值,然後將hash值以及key值本身和value傳遞到putval方法中;
final v putval
(int hash, k key, v value,
boolean onlyifabsent,
boolean evict)
//再次進行key的重複判斷
if(e.hash == hash &&
((k = e.key)
== key ||
(key != null && key.
equals
(k))))
break
; p = e;}}
//表明,記錄到具有相同元素的節點
if(e != null)
}++modcount;
//判斷當前陣列元素的個數和閾值進行比較,如果數量大於閾值則需要擴容if(
++size > threshold)
//預設情況下,第一次新增資料的時候,先會進行一次擴容後再新增資料,後續都是先新增資料在進行擴容
resize()
;afternodeinsertion
(evict)
;//這個是空函式,可以有使用者根據需要覆蓋
return null;
}
在上述的方法中,設計三種情況:第一種情況,陣列索引位置沒有鍵值對,處理方式就是直接把待新增鍵值對封裝成node新增到索引位置即可;第二種情況,如果陣列索引位置有鍵值對,而且封裝的treenode節點,處理方式是呼叫紅黑樹的插入方法,把帶新增鍵值對新增到紅黑樹中;第三種情況,同樣陣列索引位置有鍵值對,但是封裝的是node節點,處理方法就比較複雜,首先把待新增鍵值對封裝成node節點新增到鍊錶尾部,然後判斷當前鍊錶長度,如果達到閾值,就判斷是擴容還是轉換為紅黑樹;
進入getnode方法:
final node
getnode
(int hash, object key)
while
((e = e.next)
!= null);}
}return null;
}
在hashmap中,桶陣列的長度均是2的冪,閾值大小為桶陣列長度與負載因子的乘積。當hashmap中的鍵值對數量超過閾值時,就進行擴容;
擴容之後,要重新計算鍵值對的位置,並把它們移到合適的位置上去;
final node
resize()
//按舊容量或閾值的2倍計算新容量和閾值大小
elseif(
(newcap = oldcap <<1)
< maximum_capacity &&
oldcap >= default_initial_capacity)
newthr = oldthr <<1;
// double threshold
}else
if(oldthr >0)
// initial capacity was placed in threshold
//初始化時,將threshold的值賦值給newcap;
//hashmap使用threshold變數暫時儲存initialcapacity引數的值
newcap = oldthr;
else
//newthr為0時,按閾值計算公式進行計算
if(newthr ==0)
threshold = newthr;
@suppresswarnings()
//建立新的桶陣列,桶陣列的初始化也是這裡完成的
node
newtab =
(node
)new
node
[newcap]
;table = newtab;
if(oldtab != null)
else
}while
((e = next)
!= null)
;//將分組後的鍊錶對映到新桶中
if(lotail != null)
if(hitail != null)}}
}}return newtab;
}
1.計算新桶陣列的容量newcap和新閾值newthr
2.根據計算出的newcap建立新的桶陣列,桶陣列table也是這裡進行初始化的
3.將鍵值對節點重新對映到新桶陣列中,如果節點是treenode型別,則需要拆分紅黑樹;如果是普通節點,則節點按原順序進行分組
HashMap底層原始碼解析
目錄 一 分析hashmap的資料結構 1.使用陣列儲存,加快訪問速度 2.陣列中的鍊錶,解決hash衝突 3.使用紅黑樹優化鍊錶,防止大量hash衝突 二 hashmap主要原始碼解讀 三 總結 在看原始碼之前,了解一下它的資料結構和執行過程,才能更快更加有效率的讀懂原始碼。hashmap實際儲存...
HashMap底層原始碼實現
首先需要明確的是 hashmap 內部結構 可以看作是陣列和鍊錶結合組成的復合結構,陣列被分為乙個個桶 bucket 每個桶儲存有乙個或多個entry物件,每個entry物件包含三部分 key 鍵 value 值 next 指向下乙個entry 通過雜湊值決定了entry物件在這個陣列的定址 雜湊值...
HashMap底層原始碼分析
static final int default initial capacity 1 4 aka 16表示1向左移4位,2的4次方 static final int maximum capacity 1 30 hashmap陣列的最大容量 static final float default lo...