前言:HashMap是java工程師在面試過程中,碰到的概率極大的一道題,很大一部分人都是看了一些博客,記住一些答案,但是深究往往無法接招,本文就來扒一扒hashMap面試常見的點及源碼分析。
推薦分析目前爲止個人看過的分析hashMap比較好的文章。
Java 8系列之重新認識HashMap
沒有閱讀過的同學,可以先看一下這篇文章,對於hashMap的設計及原理有一個大概的瞭解,一遍不行;讀兩遍。
1、hashMap中提到了“當鏈表長度大於8時,鏈表默認轉化爲紅黑樹”,爲什麼鏈表長度爲8的時候轉化呢?
答:如果節點數量比較少遍歷鏈表速度也很快,沒必要轉成樹,而且樹還要多佔空間,那麼如何定一個臨界值呢?根據泊松分佈節點相同次數超過8個節點的概率大概是百萬分之一,再記錄增加概率也不會降低太多,最終得到一個臨界值是8,也就是說插入到hashMap中節點,真正需要轉化爲紅黑樹的其實是很少的情況。
我們可以看一下源碼做的統計:
*
* 0: 0.60653066
* 1: 0.30326533
* 2: 0.07581633
* 3: 0.01263606
* 4: 0.00157952
* 5: 0.00015795
* 6: 0.00001316
* 7: 0.00000094
* 8: 0.00000006
* more: less than 1 in ten million
*
2、我們知道隨着同一個槽中節點的減少,紅黑樹可能會退化成鏈表,jdk中定義了該值爲6,爲什麼定義爲6,而不是7呢?
/**
* 當紅黑樹元素個數小於6的時候,會從新退化爲鏈表。爲什麼?效率。
*/
static final int UNTREEIFY_THRESHOLD = 6;
答:鏈表查找的時間複雜度=,紅黑樹的查找時間複雜度是,當n=8,紅黑樹的時間是2,鏈表的時間是4,紅黑樹優於鏈表。當n=6,鏈表查詢時間是3,紅黑樹是2.585,紅黑樹基本已經沒什麼優勢了,其實對於7也沒什麼優勢,但是如果選擇7會導致鏈化和樹化頻繁切換,所以間隔調兩個元素。5、6同理,但是總得敲定一個數呀。
3、爲什麼hashMap在擴容的時候,容量大小必須是呢?
HashMap採用這種非常規設計,主要是爲了在取模和擴容時做優化,同時爲了減少衝突,HashMap定位哈希桶索引位置時,也加入了高位參與運算的過程。
擴容的時候,可以做到元素的新位置要麼是在原位置,要麼是在原位置再移動2次冪的位置。
hash值新增的那個bit是1還是0就好了,是0的話索引沒變,是1的話索引變成“原索引+oldCap”