1. 程式人生 > >一個HashMap能跟面試官扯上半個小時

一個HashMap能跟面試官扯上半個小時

### 一個HashMap能跟面試官扯上半個小時 > 《安琪拉與面試官二三事》系列文章 > [一個HashMap能跟面試官扯上半個小時](https://blog.csdn.net/zhengwangzw/article/details/104889549) > [一個synchronized跟面試官扯了半個小時](https://blog.csdn.net/zhengwangzw/article/details/105141484) >[一個volatile跟面試官扯了半個小時](https://angela.blog.csdn.net/article/details/106060526) > 《安琪拉教魯班學演算法》系列文章 > > [安琪拉教魯班放技能之動態規劃](https://blog.csdn.net/zhengwangzw/article/details/105321718) ## 前言 HashMap應該算是Java後端工程師面試的必問題,因為其中的知識點太多,很適合用來考察面試者的Java基礎。 ## 開場 **面試官**: 你先自我介紹一下吧! **安琪拉**: 我是安琪拉,草叢三婊之一,最強中單(鍾馗不服)!哦,不對,串場了,我是**,目前在--公司做--系統開發。 **面試官**: 看你簡歷上寫熟悉Java集合,HashMap用過的吧? **安琪拉**: 用過的。(還是熟悉的味道) **面試官**: 那你跟我講講HashMap的內部資料結構? **安琪拉**: 目前我用的是JDK1.8版本的,內部使用陣列 + 連結串列紅黑樹; **安琪拉**: 方便我給您畫個數據結構圖吧: ![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pbWdrci5jbi1iai51ZmlsZW9zLmNvbS85ZDkyZGRkYS1lZmRiLTRmZjctYTlmYi00MTFjMTY5MzNkYmMucG5n?x-oss-process=image/format,png) **面試官**: 那你清楚HashMap的資料插入原理嗎? **安琪拉**: 呃[做沉思狀]。我覺得還是應該畫個圖比較清楚,如下: ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/2020031712385760.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3poZW5nd2FuZ3p3,size_16,color_FFFFFF,t_70) 1. 判斷陣列是否為空,為空進行初始化; 2. 不為空,計算 k 的 hash 值,通過`(n - 1) & hash`計算應當存放在陣列中的下標 index; 3. 檢視 table[index] 是否存在資料,沒有資料就構造一個Node節點存放在 table[index] 中; 4. 存在資料,說明發生了hash衝突(存在二個節點key的hash值一樣), 繼續判斷key是否相等,相等,用新的value替換原資料(onlyIfAbsent為false); 5. 如果不相等,判斷當前節點型別是不是樹型節點,如果是樹型節點,創造樹型節點插入紅黑樹中;(如果當前節點是樹型節點證明當前已經是紅黑樹了) 6. 如果不是樹型節點,建立普通Node加入連結串列中;判斷連結串列長度是否大於 8並且陣列長度大於64, 大於的話連結串列轉換為紅黑樹; 7. 插入完成之後判斷當前節點數是否大於閾值,如果大於開始擴容為原陣列的二倍。 **面試官**: 陷入沉默,講的這麼清楚,難道是也關注了微信公眾號【安琪拉的部落格】,我繼續按照套路問,剛才你提到HashMap的初始化,那HashMap怎麼設定初始容量大小的嗎? **安琪拉**: [這也算問題??] 一般如果`new HashMap()` 不傳值,預設大小是16,負載因子是0.75, 如果自己傳入初始大小k,初始化大小為 大於k的 2的整數次方,例如如果傳10,大小為16。(補充說明:實現程式碼如下) ```java static final int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; } ``` > 補充說明:下圖是詳細過程,演算法就是讓初始二進位制右移1,2,4,8,16位,分別與自己位或,把高位第一個為1的數通過不斷右移,把高位為1的後面全變為1,最後再進行+1操作,111111 + 1 = 1000000 = $2^6$ (符合大於50並且是2的整數次冪 ) > >![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200317235036486.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3poZW5nd2FuZ3p3,size_16,color_FFFFFF,t_70) **面試官**: 你提到hash函式,你知道HashMap的雜湊函式怎麼設計的嗎? **安琪拉**: [問的還挺細] hash函式是先拿到 key 的hashcode,是一個32位的int值,然後讓hashcode的高16位和低16位進行異或操作。 ![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9pbWdrci5jbi1iai51ZmlsZW9zLmNvbS81ZmRlYTk1My0xMDg5LTQ3NjctOGYzMC1iYWYwZTZlMTk5ZmIucG5n?x-oss-process=image/format,png) **面試官**: 那你知道為什麼這麼設計嗎? **安琪拉**: [這也要問],這個也叫擾動函式,這麼設計有二點原因: 1. 一定要儘可能降低hash碰撞,越分散越好; 2. 演算法一定要儘可能高效,因為這是高頻操作, 因此採用位運算; **面試官**: 為什麼採用hashcode的高16位和低16位異或能降低hash碰撞?hash函式能不能直接用key的hashcode? [這問題有點刁鑽], 安琪拉差點原地