HashMap常見面試題整理

2022-09-13 21:12:18 字數 3673 閱讀 1635

花了三天時間來仔細閱讀hashmap的原始碼,期間補了下不少資料結構的知識,刷了不少相關的面試題並進行了整理

1.談一下hashmap的特性?

1.hashmap儲存鍵值對實現快速訪問,允許為null。key值不可重複,若key值重複則覆蓋。

2.非同步,執行緒不安全。

3.底層是hash表,不保證有序(比如插入的順序)

2.談一下hashmap的底層原理是什麼?

基於hashing的原理,jdk8後採用陣列+鍊錶+紅黑樹的資料結構。我們通過put和get儲存和獲取物件。當我們給put()方法傳遞鍵和值時,先對鍵做乙個hashcode()的計算來得到它在bucket陣列中的位置來儲存entry物件。當獲取物件時,通過get獲取到bucket的位置,再通過鍵物件的equals()方法找到正確的鍵值對,然後在返回值物件。

3.談一下hashmap中put是如何實現的?

1.計算關於key的hashcode值(與key.hashcode的高16位做異或運算)

2.如果雜湊表為空時,呼叫resize()初始化雜湊表

3.如果沒有發生碰撞,直接新增元素到雜湊表中去

4.如果發生了碰撞(hashcode值相同),進行三種判斷

4.1:若key位址相同或者equals後內容相同,則替換舊值

4.2:如果是紅黑樹結構,就呼叫樹的插入方法

4.3:鍊錶結構,迴圈遍歷直到鍊錶中某個節點為空,尾插法進行插入,插入之後判斷鍊錶個數是否到達變成紅黑樹的闕值8;也可以遍歷到有節點與插入元素的雜湊值和內容相同,進行覆蓋。

5.如果桶滿了大於閥值,則resize進行擴容

4.談一下hashmap中什麼時候需要進行擴容,擴容resize()又是如何實現的?

呼叫場景:

1.初始化陣列table

2.當陣列table的size達到闕值時即++size > load factor * capacity 時,也是在putval函式中

實現過程:(細講)

1.通過判斷舊陣列的容量是否大於0來判斷陣列是否初始化過

否:進行初始化

是,進行擴容,擴容成兩倍(小於最大值的情況下),之後在進行將元素重新進行與運算複製到新的雜湊表中

概括的講:擴容需要重新分配乙個新陣列,新陣列是老陣列的2倍長,然後遍歷整個老結構,把所有的元素挨個重新hash分配到新結構中去。

ps:可見底層資料結構用到了陣列,到最後會因為容量問題都需要進行擴容操作

5.談一下hashmap中get是如何實現的?

對key的hashcode進行hashing,與運算計算下標獲取bucket位置,如果在桶的首位上就可以找到就直接返回,否則在樹中找或者鍊錶中遍歷找,如果有hash衝突,則利用equals方法去遍歷鍊錶查詢節點。

6.談一下hashmap中hash函式是怎麼實現的?還有哪些hash函式的實現方式?

對key的hashcode做hash操作,與高16位做異或運算

還有平方取中法,除留餘數法,偽隨機數法

7.為什麼不直接將key作為雜湊值而是與高16位做異或運算?

因為陣列位置的確定用的是與運算,僅僅最後四位有效,設計者將key的雜湊值與高16為做異或運算使得在做&運算確定陣列的插入位置時,此時的低位實際是高位與低位的結合,增加了隨機性,減少了雜湊碰撞的次數。

hashmap預設初始化長度為16,並且每次自動擴充套件或者是手動初始化容量時,必須是2的冪。

8.為什麼是16?為什麼必須是2的冪?如果輸入值不是2的冪比如10會怎麼樣?

1.為了資料的均勻分布,減少雜湊碰撞。因為確定陣列位置是用的位運算,若資料不是2的次冪則會增加雜湊碰撞的次數和浪費陣列空間。(ps:其實若不考慮效率,求餘也可以就不用位運算了也不用長度必需為2的冪次)

2.輸入資料若不是2的冪,hashmap通過一通位移運算和或運算得到的肯定是2的冪次數,並且是離那個數最近的數字

9.談一下當兩個物件的hashcode相等時會怎麼樣?

會產生雜湊碰撞,若key值相同則替換舊值,不然鏈結到鍊錶後面,鍊錶長度超過闕值8就轉為紅黑樹儲存

10.如果兩個鍵的hashcode相同,你如何獲取值物件?

hashcode相同,通過equals比較內容獲取值物件

11."如果hashmap的大小超過了負載因子(load factor)定義的容量,怎麼辦?

超過闕值會進行擴容操作,概括的講就是擴容後的陣列大小是原陣列的2倍,將原來的元素重新hashing放入到新的雜湊表中去。

12.hashmap和hashtable的區別

相同點:都是儲存key-value鍵值對的

不同點:

13.請解釋一下hashmap的引數loadfactor,它的作用是什麼?

loadfactor表示hashmap的擁擠程度,影響hash操作到同乙個陣列位置的概率。預設loadfactor等於0.75,當hashmap裡面容納的元素已經達到hashmap陣列長度的75%時,表示hashmap太擠了,需要擴容,在hashmap的構造器中可以定製loadfactor。

14.傳統hashmap的缺點(為什麼引入紅黑樹?):

jdk 1.8 以前 hashmap 的實現是 陣列+鍊錶,即使雜湊函式取得再好,也很難達到元素百分百均勻分布。當 hashmap 中有大量的元素都存放到同乙個桶中時,這個桶下有一條長長的鍊錶,這個時候 hashmap 就相當於乙個單鏈表,假如單鏈表有 n 個元素,遍歷的時間複雜度就是 o(n),完全失去了它的優勢。針對這種情況,jdk 1.8 中引入了 紅黑樹(查詢時間複雜度為 o(logn))來優化這個問題。

15. 平時在使用hashmap時一般使用什麼型別的元素作為key?

選擇integer,string這種不可變的型別,像對string的一切操作都是新建乙個string物件,對新的物件進行拼接分割等,這些類已經很規範的覆寫了hashcode()以及equals()方法。作為不可變類天生是執行緒安全的,

原始碼解析閱讀:

1.2. 

3. 4. 

5.

HashMap常見面試題

1.你知道hashmap的工作原理嗎?你知道hashmap的get 方法的工作原理嗎?hashmap基於hashing原理,我們通過put 和get 方法儲存和獲取物件。當我們將鍵值對傳遞給put 方法時,它呼叫鍵物件的hashcode 方法來計算hashcode,讓後找到bucket位置來儲存en...

HashMap常見面試題

物件 key和value是否允許為空 是否執行緒安全 hashmap key和value都允許為null 否hashtable key和value都不允許為null 是concurrenthashmap key和value都不允許為null 是jdk1.7 超過擴容的閾值 發生碰撞 jdk1.8 超...

常見面試題整理

題目 如下為型別cmystring的宣告,請為該型別新增賦值運算子函式。class cmystring 注意點 1.返回值是否為該型別的引用。如果為該型別引用則可連續賦值。如果返回void,則無法通過編譯 2.傳入引數是否宣告為常量引用。如果傳入引數不是常量引用,則會有一次非必要的拷貝構造函式呼叫 ...