HashMap(JDK8)面試突擊

其實剛開始接觸HashMap的時候看別人博客以及源碼是真的一頭霧水,最後還是決定找視頻入下門比較合適

https://www.bilibili.com/video/av24032788

關於HashMap的面試題這兩篇講的不錯:

https://blog.csdn.net/LE_912/article/details/80599869

https://blog.csdn.net/u012512634/article/details/72735183

關於HahMap中的變量解釋這篇講的不錯:

https://www.hollischuang.com/archives/2416

簡單總結下HashMap:

HashMap底層數據結構:數組+鏈表+紅黑樹,可以接受null的key和value值.數組默認初始化大小爲16,當鏈接長度大於8的時候就會轉換爲紅黑樹,實現logn的複雜度查詢,如果小於6就會再次轉換爲鏈表.
其中的結構單體是entry,包括四個元素:key,value,next,hash值.
還有一些全局變量:
HashMap中size表示當前共有多少個KV對,capacity表示當前HashMap的容量是多少,默認值是16,每次擴容都是成倍的。loadFactor是裝載因子,當Map中元素個數超過loadFactor* capacity的值時,會觸發擴容。loadFactor* capacity可以用threshold表示。

如何擴容:
默認數組大小爲16,擴容每次都是兩倍,擴容因子是0.75,即當數組容量達到12的時候就擴容,擴容的時候會創建一個新的數組,然後將原來數組的entry們複製到新數組中,原數組需要null,這樣纔會被gc回收.
注意之前的entry的位置只有兩種情況,一種是原來位置,一種是原來位置+原容量大小.這個位置的判斷是hash值&初始容量即16,如果高位爲0則原來位置,如果高位爲1則位置變爲原來位置+擴容大小.

如何查找:
首先根據key的hashcode()找到數組的下標,然後根據key的equals()找到數組鏈表上的對應的entry.

注意這裏首先獲取hash值有個函數是將高16位和低16位做異或運算,得到hash值.根據hash值&(容量-1)找到數組下標,如果碰撞了就使用equals.
問題:爲什麼高低位要異或?
因爲如果不異或操作,那得到的hash值只保留了低位的特性,和(容量-1)&操作的時候如果數組容量小,容易增加碰撞概率,因爲只和低位的&操作,所以需要將hash保留高位特性,這樣得到的hash值可以儘量讓Node落點分佈均勻,減少碰撞概率.
問題:爲什麼數組容量要2的冪次方?
因爲尋找數組下標是依靠這個代碼:數組[hash值&(容量-1)]

  1. 容量-1是爲了讓得到的下標結果控制在數組大小範圍內,不越界.
  2. 二進制位運算的時候2冪次方-1的結果肯定是111… 可以合理分配數組的位置,如果是其他數-1的話,二進制肯定會有0 如 1101 這樣子數組下標判斷的時候只會考慮到第1,2,4位, 而第三位就會被忽略,如1011等無法訪問,導致數組下標分佈不均勻.

如何添加:

  1. 根據key的hashcode()找到數組的下標,
  2. 如果沒有碰撞就將entry加入到其中,
  3. 如果碰撞了,追加到鏈表結尾JDK8,在JDK7的話是添加到首部,這裏是不一樣的.
  4. 如果鏈表的長度超過了閾值即爲8,就會將鏈表轉換爲紅黑樹
  5. 如果已經存在節點,就替換掉舊值
  6. 數組滿了(容量*加載因子) 就需要resize擴容.

hashMap和hashTable區別?

  1. hashMap是非線程安全的,hashtable是線程安全的,其實就是在操作方法即get()和put()上加上synchronized.
  2. hashMap可以添加key和value爲null的值,而hashTable不行.

如何將hashMap變爲線程安全呢?
可以使用Collections.synchronizedMap(map)方法.
什麼是ConcurentHashMap?
現在用ConcurrentHashMap代替hashTable.
ConcurrentHashMap採用分段鎖,內部分爲很多段,每段都相當於一個小的HashTable,他們有自己的鎖,只要多個修改操作發生在不同的段上,就可以併發進行.

題外話:
常考ArrayList和Vector區別?
vector是線程安全的,它在add方法的時候使用了同步函數,方法上加了synchronized關鍵字,而ArrayList的add方法沒有添加這個關鍵字.
當存儲空間不足的時候,ArrayList默認大小變爲原來的1.5倍,而vector默認大小變爲原來的2倍.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章