更新時(shí)間:2023-02-03 14:12:13 來(lái)源:動(dòng)力節(jié)點(diǎn) 瀏覽2200次
現(xiàn)在網(wǎng)上有關(guān)hashmap面試題的資料可以說(shuō)是五花八門(mén)的,有的只有問(wèn)題沒(méi)有回答,有的有回答沒(méi)有解答思路,這就讓我們很難參考了。在我們的面試中除了要征服面試官,讓面試官看到我們的技術(shù)功底,也是面試者之間的pk,面試的人再多,企業(yè)也只招收那么幾名,所以,我們要展現(xiàn)出最好的優(yōu)勢(shì)。從面試題下手,可以很大程度上增加我們的就業(yè)機(jī)會(huì)。

1.HashMap的擴(kuò)容方式?負(fù)載因子是多少?為什是這么多?
加載因子設(shè)置為0.75而不是1,是因?yàn)樵O(shè)置過(guò)大,桶中鍵值對(duì)碰撞的幾率就會(huì)越大,同一個(gè)桶位置可能會(huì)存放好幾個(gè)value值,這樣就會(huì)增加搜索的時(shí)間,性能下降,設(shè)置過(guò)小也不合適,如果是0.1,那么10個(gè)桶,threshold為1,你放兩個(gè)鍵值對(duì)就要擴(kuò)容,太浪費(fèi)空間了。
2.HashMap的主要參數(shù)都有哪些?
//默認(rèn)的map大小,為2的n次冪
static final int DEFAULT_INITIAL_CAPACITY(默認(rèn)初始容量) = 1 << 4; // aka 16
// 最大容量,指定的值超過(guò) 2的30次冪,默認(rèn)使用這個(gè)值
static final int MAXIMUM_CAPACITY (最大容量)= 1 << 30;
//在構(gòu)造函數(shù)中沒(méi)有指定時(shí)使用的負(fù)載因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//當(dāng)鏈表長(zhǎng)度為8時(shí),使用以紅黑樹(shù)代替鏈表,紅黑樹(shù)的結(jié)點(diǎn)是鏈表長(zhǎng)度的兩倍,當(dāng)比較短的時(shí)候,使用紅黑樹(shù)的效率其實(shí)并不高,根據(jù)泊松分布公式的統(tǒng)計(jì)結(jié)果,在結(jié)點(diǎn)數(shù)達(dá)到8時(shí),適合使用紅黑樹(shù)
static final int TREEIFY_THRESHOLD(恐嚇的閾值) = 8;
// 紅黑樹(shù)轉(zhuǎn)為鏈表的閾值
static final int UNTREEIFY_THRESHOLD (非恐嚇的閾值)= 6;
//鏈表轉(zhuǎn)紅黑樹(shù)時(shí)數(shù)組的大小的閾值,即數(shù)組大小大于這個(gè)數(shù)字時(shí)且鏈表長(zhǎng)度大于8才會(huì)轉(zhuǎn)為紅黑樹(shù),
//在數(shù)組長(zhǎng)度小于64,不會(huì)轉(zhuǎn),而是進(jìn)行擴(kuò)容
static final int MIN_TREEIFY_CAPACITY = 64(小的恐嚇容量);
3.HashMap是怎么處理hash碰撞的?
如果key相同,則會(huì)替換key對(duì)應(yīng)的內(nèi)容最最小值,key不相同,則接到后面的鏈表,如果鏈表長(zhǎng)度到達(dá)8且數(shù)組的長(zhǎng)度大于64時(shí),則將鏈表轉(zhuǎn)為紅黑樹(shù),如果數(shù)組長(zhǎng)度小于64,則是進(jìn)行擴(kuò)容
4.hash的計(jì)算規(guī)則?
將對(duì)象的hashcode()方法返回的hash值,進(jìn)行無(wú)符號(hào)的右移16位,并與原來(lái)的hash值進(jìn)行按位異或操作,目的是將hash的低16bit和高16bit做了一個(gè)異或,使返回的值足夠散列
在get和put的過(guò)程中,計(jì)算下標(biāo)時(shí),先對(duì)hashCode進(jìn)行hash操作,然后再通過(guò)hash值進(jìn)一步計(jì)算下標(biāo)。
5.如何解決初始化,輸入的值不是2的n次冪
/**
* Returns a power of two size for the given target capacity.
*/
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;
}
6.HashMap的數(shù)據(jù)插入原理是怎樣的
面試者:如果你能按以下思路回答,堪稱(chēng)完美!
先判斷數(shù)組是否為空,為空進(jìn)行初始化;
不為空,計(jì)算 k 的 hash 值,通過(guò)(n - 1) & hash計(jì)算應(yīng)當(dāng)存放在數(shù)組中的下標(biāo) index;
查看 table[index] 是否存在數(shù)據(jù),沒(méi)有數(shù)據(jù)就構(gòu)造一個(gè)Node節(jié)點(diǎn)存放在 table[index] 中;
存在數(shù)據(jù),說(shuō)明發(fā)生了hash沖突(存在二個(gè)節(jié)點(diǎn)key的hash值一樣), 繼續(xù)判斷key是否相等,相等,用新的value替換原數(shù)據(jù)(onlyIfAbsent為false);
如果不相等,判斷當(dāng)前節(jié)點(diǎn)類(lèi)型是不是樹(shù)型節(jié)點(diǎn),如果是樹(shù)型節(jié)點(diǎn),創(chuàng)建樹(shù)型節(jié)點(diǎn)插入紅黑樹(shù)中;(如果當(dāng)前節(jié)點(diǎn)是樹(shù)型節(jié)點(diǎn)證明當(dāng)前已經(jīng)是紅黑樹(shù)了);
如果不是樹(shù)型節(jié)點(diǎn),創(chuàng)建普通Node加入鏈表中;判斷鏈表長(zhǎng)度是否大于 8并且數(shù)組長(zhǎng)度是不是大于64,大于的話(huà)鏈表轉(zhuǎn)換為紅黑樹(shù);
插入完成之后判斷當(dāng)前節(jié)點(diǎn)數(shù)是否大于閾值,如果大于開(kāi)始擴(kuò)容為原數(shù)組的二倍。
以上7個(gè)步驟,不一定完全死記硬背,咱也背不下來(lái),因此威哥的邏輯還是基于理解本質(zhì)。
7.多線(xiàn)程情況下,調(diào)整 HashMap 的大小會(huì)有什么問(wèn)題?
由于線(xiàn)程不安全的原因,在多線(xiàn)程條件下調(diào)整 HashMap 的大小時(shí)會(huì)存在多個(gè) HashMap 對(duì)象的競(jìng)爭(zhēng)關(guān)系,不知道要給哪一個(gè)調(diào)整大小。如此一來(lái),多線(xiàn)程情況調(diào)整 HashMap 的大小就會(huì)陷入死循環(huán)的情況,在 Java1.5 以后就增加了 ConcurrentHashMap 的對(duì)象解決多線(xiàn)程等問(wèn)題。
8.HashMap擴(kuò)容機(jī)制是怎么樣的,JDK7 與JDK8有什么不同嗎?
首先,我們需要知道HashMap為什么需要擴(kuò)容,道理很簡(jiǎn)單,HashMap底層是用數(shù)組+鏈表實(shí)現(xiàn)的,而數(shù)組是預(yù)先就已經(jīng)分配好內(nèi)存的,如果需要對(duì)數(shù)組進(jìn)行擴(kuò)容,需要重新開(kāi)辟一個(gè)新的數(shù)組再將舊數(shù)組上的元素進(jìn)行轉(zhuǎn)移,如果不進(jìn)行擴(kuò)容,那么會(huì)導(dǎo)致HashMap的鏈表過(guò)長(zhǎng),查詢(xún)效率降低,所以需要對(duì)數(shù)組進(jìn)行擴(kuò)容。
在JDK7中,HashMap擴(kuò)容的條件是 (size >= threshold) && (null !=table[bucketIndex]) , size 為HashMap當(dāng)前的容量, threshold 初始化值為12, table[bucketIndex] 代表所put進(jìn)來(lái)的key所對(duì)應(yīng)的數(shù)組上的元素,所以在JDK7中擴(kuò)容條件是當(dāng)當(dāng)Put操操作傳入的 作傳入的Key值所對(duì)應(yīng)的數(shù)組位置上不為空時(shí)并且當(dāng)前容量大于等于了擴(kuò)容的閾值時(shí)才進(jìn)行擴(kuò)容 值所對(duì)應(yīng)的數(shù)組位置上不為空時(shí)并且當(dāng)前容量大于等于了擴(kuò)容的閾值時(shí)才進(jìn)行擴(kuò)容,JDK7中的擴(kuò)容思路是:開(kāi)辟一個(gè)新的數(shù)組,數(shù)組大小為原數(shù)組的兩倍,然后再將數(shù)組上的鏈表與元素轉(zhuǎn)移到新數(shù)組上,此過(guò)程可能會(huì)出現(xiàn)死鎖。
JDK8中的擴(kuò)容條件比JDK7中要少,只有當(dāng)前容量大于等于了擴(kuò)容的閾值時(shí)才進(jìn)行擴(kuò)容 當(dāng)前容量大于等于了擴(kuò)容的閾值時(shí)才進(jìn)行擴(kuò)容,并且擴(kuò)容的思路也發(fā)生了變化,思路比較復(fù)雜。
以上就是“92%的同學(xué)都在搜索的hashmap面試題”,你能回答上來(lái)嗎?如果想要了解更多的Java面試題相關(guān)內(nèi)容,可以關(guān)注動(dòng)力節(jié)點(diǎn)Java官網(wǎng)。
相關(guān)閱讀
Java實(shí)驗(yàn)班
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
Java就業(yè)班
有基礎(chǔ) 直達(dá)就業(yè)
Java夜校直播班
業(yè)余時(shí)間 高薪轉(zhuǎn)行
Java在職加薪班
工作1~3年,加薪神器
Java架構(gòu)師班
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問(wèn)老師會(huì)電話(huà)與您溝通安排學(xué)習(xí)