1. 程式人生 > >【大廠面試08期】談一談你對HashMap的理解?

【大廠面試08期】談一談你對HashMap的理解?

# 摘要 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) {