您好,登錄后才能下訂單哦!
這篇文章主要介紹“有哪些HashMap面試專題”,在日常操作中,相信很多人在有哪些HashMap面試專題問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”有哪些HashMap面試專題”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
將任意長度的輸入通過散列算法之后映射成固定長度的輸出。
當關(guān)鍵字集合很大時(key的數(shù)量很多的時候),關(guān)鍵字值不同的元素可能會映像到哈希表的同一地址上,即K1!=K2,但f(K1)=f(K2),這種現(xiàn)象稱為hash沖突,實際中沖突是不可避免的,只能通過改進哈希函數(shù)的性能來減少沖突。
(4)盡可能要分散,因為在table中slot大部分都處于空閑狀態(tài)時要盡可能降低Hash沖突
JDK1.8:
(1)數(shù)組+鏈表+紅黑樹構(gòu)成,每個數(shù)據(jù)單元為一個Node結(jié)構(gòu),Node結(jié)構(gòu)中有key字段、value字段、next字段、hash字段
(2)next字段就是發(fā)生Hash沖突的時候,當前桶位中的Node與沖突Node連接成一個鏈表所需要的字段
JDK1.7:
數(shù)組+鏈表
在JDK 8中,關(guān)于默認容量的定義為:static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //16 ,其故意把16寫成1<<4,就是提醒開發(fā)者,這個地方要是2的冪。
(1)為啥用位運算呢?直接寫16不好么?
這樣是為了位運算的方便,位與運算比算數(shù)計算的效率高了很多,之所以選擇16,是為了服務(wù)將Key映射到index的算法。
(2)那為啥用16不用別的呢?
因為在使用不是2的冪的數(shù)字的時候,Length-1的值是所有二進制位全為1,這種情況下,index的結(jié)果等同于HashCode后幾位的值。這個值既不能太小,也不能太大。
太小了就有可能頻繁發(fā)生擴容,影響效率,太大了又浪費空間,不劃算。
只要輸入的HashCode本身分布均勻,Hash算法的結(jié)果就是均勻的。
這是為了實現(xiàn)均勻分布。
散列表是懶加載機制,只有在第一次put數(shù)據(jù)的時候才創(chuàng)建(JDK1.8,JDK1.7是直接加載散列表)
(1)默認為0.75,用于計算擴容閾值
(2)loadFactor是負載因子,表示HashMap滿的程度,默認值為0.75f,設(shè)置成0.75有一個好處,那就是0.75正好是3/4,而capacity又是2的冪。所以,兩個數(shù)的乘積都是整數(shù)。
(3)影響擴容主要有兩個因素:
??Capacity:HashMap當前長度。
??LoadFactor:負載因子,默認值0.75f。
??怎么理解呢,就比如當前的容量大小為100,當你存進第76個的時候,判斷發(fā)現(xiàn)大于擴容閾值100*0.75=75需要進行resize了,那就進行擴容,但是HashMap的擴容也不是簡單的擴大點容量這么簡單的。
分為兩步
(1)擴容:創(chuàng)建一個新的Entry空數(shù)組,長度是原數(shù)組的2倍。
(2)ReHash:遍歷原Entry數(shù)組,把所有的Entry重新Hash到新數(shù)組。
為什么要重新Hash呢,直接復(fù)制過去不香么?
是因為長度擴大以后,Hash的規(guī)則也隨之改變。
比如原來長度(Length)是8你位運算出來的值是2 ,新的長度是16你位運算出來的值明顯不一樣了。
(1)鏈表長度達到8
(2)當前散列表長度達到64
以上兩個條件同時滿足鏈表才會轉(zhuǎn)化為紅黑樹,如果僅僅鏈表長度達到8,它不會發(fā)生鏈表轉(zhuǎn)紅黑樹,只會發(fā)生一次散列表擴容(resize)
不是的,通過key的hashcode的高16位異或低16位得到的新值,這樣即使數(shù)組table的length比較小的時候,也能保證高低bit都參與到Hash的計算中,避免高16位浪費沒起到作用,盡可能的得到一個均勻分布的hash。
因為在java中,所有的對象都是繼承于Object類。Ojbect類中有兩個方法equals、hashCode,這兩個方法都是用來比較兩個對象是否相等的。
在未重寫equals方法我們是繼承了object的equals方法,那里的 equals是比較兩個對象的內(nèi)存地址,顯然我們new了2個對象內(nèi)存地址肯定不一樣
比如發(fā)生Hash沖突的時候,我們?nèi)et,他就是根據(jù)key去hash然后計算出index,找到了2,那我怎么找到具體的”電腦“還是”腦電“呢?
equals!是的,所以如果我們對equals方法進行了重寫,建議一定要對hashCode方法重寫,以保證相同的對象返回相同的hash值,不同的對象返回不同的hash值。
這就涉及到拒接服務(wù)攻擊了,比如某些人通過找到你的hash碰撞值,來讓你的HashMap不斷地產(chǎn)生碰撞,那么相同key位置的鏈表就會不斷增長,當你需要對這個HashMap的相應(yīng)位置進行查詢的時候,就會去循環(huán)遍歷這個超級大的鏈表,性能及其地下。java8使用紅黑樹來替代超過8個節(jié)點數(shù)的鏈表后,查詢方式性能得到了很好的提升,從原來的是O(n)到O(logn),容器中節(jié)點分布在hash桶中的頻率遵循泊松分布,桶的長度超過8的概率非常非常?。s為10萬分之一),所以作者應(yīng)該是根據(jù)概率統(tǒng)計而選擇了8作為閥值。
(1)JDK1.7用的是頭插法,而JDK1.8及之后使用的都是尾插法,那么他們?yōu)槭裁匆@樣做呢?
因為JDK1.7是用單鏈表進行的縱向延伸,當采用頭插法時會容易出現(xiàn)逆序且環(huán)形鏈表死循環(huán)問題。但是在JDK1.8之后是因為加入了紅黑樹使用尾插法,能夠避免出現(xiàn)逆序且鏈表死循環(huán)的問題。
(2)擴容后數(shù)據(jù)存儲位置的計算方式也不一樣:1. 在JDK1.7的時候是直接用hash值和需要擴容的二進制數(shù)進行&(這里就是為什么擴容的時候為啥一定必須是2的多少次冪的原因所在,因為如果只有2的n次冪的情況時最后一位二進制數(shù)才一定是1,這樣能最大程度減少hash碰撞)(hash值 & length-1)
(1)在jdk1.7中,在多線程環(huán)境下,擴容時會造成環(huán)形鏈或數(shù)據(jù)丟失。
(2)在jdk1.8中,在多線程環(huán)境下,會發(fā)生數(shù)據(jù)覆蓋的情況。
到此,關(guān)于“有哪些HashMap面試專題”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。