這篇文章講的是HashMap,將會深入到原始碼層面去分析HashMap,加深對HashMap的理解

1.1 HashMap的屬性
首先是定義的一些常量

然后是變數

接下來看一下HashMap中的一個內部類Node

可以看到Node是鏈表結構,這是因為HashMap是以陣列+鏈表的形式來實作的
1.2 構造方法
HashMap有4種構造方法

這里挑第一種構造方法來講

可以看到構造方法中首先判斷初始大小是否合理,并且初始化裝載因子和閾值
初始化閾值時呼叫了 tableSizeFor() 這個方法,點進去看

從注釋中可以知道這個方法會回傳一個2的整數冪
1.3 put()方法
put 方法是 HashMap 中比較重要的一個方法,我們一起來看看

可以看到它呼叫了 putVal() 方法,使用 hash() 方法用 key 計算 哈希值,那就看看 hash() 方法怎么計算哈希值的

可以看到hash()方法中得到key的哈希值并且與該值的高16位做異或運算,為什么要做異或運算呢?
因為表的默認初始容量為16,我們要把元素放到散串列中,也就是放到0-15位置上,也就是 tab[i = (n - 1) & hash],而在做 & 運算的時候,只有后四位有效,如果key的哈希值高位變化很大,低位變化很小,那么會導致計算出來的hash值很容易相同
而使key的哈希值的高位也參與運算,可以有效地減少哈希碰撞的可能性
再來看 putVal() 方法


可以看到首先當表為null時,呼叫resize()初始化
如果沒有發生碰撞,直接將元素添加進表中
否則如果是紅黑樹結構,就呼叫樹的插入方法
如果是鏈表結構,就尋找key映射的節點,就記錄下來并退出回圈,如果沒有找到就在鏈表尾部插入節點,如果插入后發現臨界值大于TREEIFY_THRESHOLD,則轉化為紅黑樹
最后使用新值覆寫舊值,并回傳舊值
1.4 get()方法

可以看到呼叫了getNode()方法來取值,點進去看看

可以看到如果在桶的首位就可以找到的話那么就直接回傳
否則就遍歷紅黑樹和鏈表進行尋找
1.5 remove()方法

可以看到呼叫了removeNode()方法來完成洗掉,點進去看看


可以看到如果在桶的首位就找到了要洗掉的元素,就記錄下來
否則就去紅黑樹或鏈表中查找
最后分三種情況洗掉:1.鏈表 2.紅黑樹 3.在桶的首位
1.6 執行緒安全性
HashMap是執行緒不安全的,不要在并發的環境中同時操作HashMap,與之對應的是執行緒安全的HashTable,但是性能太低不建議使用,推薦使用ConcurrentHashMap
1.7 總結
HashMap是基于陣列+鏈表+紅黑樹來實作的
HashMap中擴容是非常耗費性能的操作,所以在初始化HashMap時最好定一個初始值
裝載因子的默認值是0.75,是可以修改的,但是不建議修改,因為過大或過小都會對性能造成影響
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/4664.html
標籤:其他
