【大廠面試08期】談一談你對HashMap的理解?
阿新 • • 發佈:2020-06-17
# 摘要
HashMap的原理也是大廠面試中經常會涉及的問題,同時也是工作中常用到的Java容器,本文主要通過對以下問題進行分析講解,來幫助大家理解HashMap的原理。
1.HashMap新增一個鍵值對的過程是怎麼樣的?
2.為什麼說HashMap不是執行緒安全的?
3.為什麼要一起重寫hashCode()和equal()方法?
# HashMap新增一個鍵值對的過程是怎麼樣的?
這是網上找的一張流程圖,可以結合著步驟來看這個流程圖,瞭解新增鍵值對的過程。
![](https://user-gold-cdn.xitu.io/2020/6/16/172bd032609073ed?w=800&h=542&f=png&s=95778)
## 1.初始化table
判斷table是否為空或為null,否則執行resize()方法(resize方法一般是擴容時呼叫,也可以呼叫來初始化table)。
## 2.計算hash值
根據鍵值key計算hash值。(因為hashCode是一個int型別的變數,是4位元組,32位,所以這裡會將hashCode的低16位與高16位進行一個異或運算,來保留高位的特徵,以便於得到的hash值更加均勻分佈)
```java
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
```
## 3.插入或更新節點
根據(n - 1) & hash計算得到插入的陣列下標i,然後進行判斷
### table[i]==null
那麼說明當前陣列下標下,沒有hash衝突的元素,直接新建節點新增。
### table[i].hash == hash &&(table[i]== key || (key != null && key.equals(table[i].key)))
判斷table[i]的首個元素是否和key一樣,如果相同直接更新value。
### table[i] instanceof TreeNode
判斷table[i] 是否為treeNode,即table[i] 是否是紅黑樹,如果是紅黑樹,則直接在樹中插入鍵值對。
### 其他情況
上面的判斷條件都不滿足,說明table[i]儲存的是一個連結串列,那麼遍歷連結串列,判斷是否存在已有元素的key與插入鍵值對的key相等,如果是,那麼更新value,如果沒有,那麼在連結串列末尾插入一個新節點。插入之後判斷連結串列長度是否大於8,大於8的話把連結串列轉換為紅黑樹。
## 4.擴容
插入成功後,判斷實際存在的鍵值對數量size是否超多了最大容量threshold(一般是陣列長度*負載因子0.75),如果超過,進行擴容。
原始碼如下:
![](https://user-gold-cdn.xitu.io/2020/6/16/172bd6fe0c9b62a5?w=1645&h=3870&f=png&s=725352)
# 2.為什麼說HashMap不是執行緒安全的?
其實通過學習HashMap新增鍵值對的方法,我們可以看到整個方法內都沒有使用到鎖,所以一旦多線併發訪問,就有可能造成資料不一致的問題,
例如:
如果有兩個新增鍵值對的執行緒都執行到`if ((tab = table) == null || (n = tab.length) == 0)`這行語句,都對table變數進行陣列初始化,就會造成已經初始化好的陣列table被覆蓋,然後前面初始化的執行緒會將鍵值對新增到之前初始化的陣列中去,造成鍵值對丟失。
```java
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {