Android面試題----HashMap深度剖析

HashMap,一個大小廠都會問的知識點墓捻。下面結(jié)合網(wǎng)上搜羅的一些信息抖仅,整理出一份比較全面的Hashmap相關(guān)面試資料:

  1. HashMap與HashTable的區(qū)別?

主要區(qū)別有三點:線程安全性毙替,同步岸售,以及速度。

HashTable是線程安全的厂画,而HashMap不是凸丸;
HashMap中允許存在null鍵和null值,而HashTable中不允許

單線程環(huán)境下HashMap的速度快袱院。多線程環(huán)境下屎慢,java 5提供了ConcurrentHashmap,它是HashTable的替代忽洛,比HashTable的擴展性更好腻惠。
2.HashMap的工作原理是什么?or HashMap的get()方法工作原理欲虚?

HashMap基于hashing原理集灌,我們通過put()和get()方法儲存和獲取對象。當我們將鍵值對傳遞給put()方法時复哆,它調(diào)用鍵對象的hashCode()方法來計算hashcode欣喧,讓后找到bucket位置來儲存值對象。當獲取對象時梯找,通過鍵對象的equals()方法找到正確的鍵值對唆阿,然后返回值對象。HashMap使用LinkedList來解決碰撞問題锈锤,當發(fā)生碰撞了驯鳖,對象將會儲存在LinkedList的下一個節(jié)點中。 HashMap在每個LinkedList節(jié)點中儲存鍵值對對象久免。

3.兩個對象的hashcode相同時會發(fā)生什么浅辙?

因為hashcode相同,所以它們的bucket位置相同妄壶,‘碰撞’會發(fā)生摔握。它們會儲存在同一個bucket位置的LinkedList中。鍵對象的equals()方法用來找到鍵值對丁寄。

4.兩個鍵的hashcode相同時氨淌,如何獲取值對象泊愧?

當我們調(diào)用get()方法,HashMap會使用鍵對象的hashcode找到bucket位置盛正,然后獲取值對象删咱。如果有兩個值對象儲存在同一個bucket,會調(diào)用keys.equals()方法遍歷LinkedList豪筝,直到找到正確的節(jié)點痰滋,最終找到要找的值對象。

5.如果HashMap的大小超過了負載因子定義的容量怎么辦续崖?

默認的負載因子大小為0.75敲街,也就是說,當一個map填滿了75%的bucket時候严望,和其它集合類(如ArrayList等)一樣多艇,將會創(chuàng)建原來HashMap大小的兩倍的bucket數(shù)組,來重新調(diào)整map的大小像吻,并將原來的對象放入新的bucket數(shù)組中峻黍。這個過程叫作rehashing,因為它調(diào)用hash方法找到新的bucket位置拨匆。

6.多線程環(huán)境下姆涩,重新調(diào)整HashMap大小存在什么問題?

多線程環(huán)境下惭每,當重新調(diào)整HashMap大小的時候骨饿,存在條件競爭,因為如果兩個線程都發(fā)現(xiàn)HashMap需要重新調(diào)整大小了台腥,它們會同時試著調(diào)整大小样刷。在調(diào)整大小的過程中,存儲在LinkedList中的元素的次序會反過來览爵,因為移動到新的bucket位置的時候,HashMap并不會將元素放在LinkedList的尾部镇饮,而是放在頭部蜓竹,這是為了避免尾部遍歷(tail traversing)。如果條件競爭發(fā)生了储藐,那么就死循環(huán)了俱济。

所在,不能在多線程環(huán)境下使用Hashmap钙勃。

7.為什么String, Interger這樣的wrapper類適合作為鍵蛛碌?

如果兩個不相等的對象返回不同的hashcode的話,那么碰撞的幾率就會小些辖源,這樣就能提高HashMap的性能蔚携,也就適合做Hashmap的鍵希太。因為獲取對象的時候要用到equals()和hashCode()方法,鍵對象正確的重寫這兩個方法是非常重要的酝蜒。

因此誊辉,String,Interger這樣的wrapper類作為HashMap的鍵是再適合不過了亡脑,而且String最為常用堕澄。因為String是不可變的,也是final的霉咨,而且已經(jīng)重寫了equals()和hashCode()方法了蛙紫。其他的wrapper類也有這個特點。不可變性是必要的途戒,因為為了要計算hashCode()坑傅,就要防止鍵值改變,如果鍵值在放入時和獲取時返回不同的hashcode的話棺滞,那么就不能從HashMap中找到你想要的對象裁蚁。

8.可以用自定義對象作為鍵嗎?

這是前一個問題的延伸继准。當然你可能使用任何對象作為鍵枉证,只要它遵守了equals()和hashCode()方法的定義規(guī)則,并且當對象插入到Map中之后將不會再改變了移必。如果這個自定義對象時不可變的室谚,那么它已經(jīng)滿足了作為鍵的條件,因為當它創(chuàng)建之后就已經(jīng)不能改變了崔泵。

9.可以使用CocurrentHashMap來代替HashTable嗎秒赤?

可以。我們知道HashTable是synchronized的憎瘸,但是ConcurrentHashMap同步性能更好入篮,因為它僅僅根據(jù)同步級別對map的一部分進行上鎖。ConcurrentHashMap當然可以代替HashTable幌甘,但是HashTable提供更強的線程安全性潮售,效率要低。

10.能否讓HashMap同步锅风?

Hashmap可以通過下面的語句進行同步:

Map map = Collections.synchronizedMap(hashmap);
Collections 內(nèi)部有一個實現(xiàn)了 Map 接口的 SynchronizedMap 內(nèi)部類酥诽,這是一個實現(xiàn)線程同步的 map 類,具體線程同步就是在所有的方法實現(xiàn)中都使用 synhronized 塊達到線程同步皱埠,不過具體的方法實現(xiàn)統(tǒng)統(tǒng)使用 synchronizedMap 方法傳遞進去 map 來完成肮帐。里面的實現(xiàn)是典型的裝飾模式。

11.ConcurrentHashMap的并發(fā)機制边器?

ConcurrentHashMap 引入了分段鎖的機制训枢,該機制對并發(fā)控制做了優(yōu)化 托修。

ConcurrentHashMap是支持并發(fā)讀寫的HashMap,它的特點是讀取數(shù)據(jù)時無需加鎖肮砾,寫數(shù)據(jù)時可以保證加鎖粒度盡可能的小诀黍。由于其內(nèi)部采用“分段存儲”,只需對要進行寫操作的數(shù)據(jù)所在的“段”進行加鎖仗处。
ConcurrentHashMap 類中包含兩個靜態(tài)內(nèi)部類 HashEntry 和 Segment眯勾。HashEntry 用來封裝映射表的鍵 / 值對;Segment 用來充當鎖的角色婆誓,每個 Segment 對象守護整個散列映射表的若干個桶吃环。每個桶是由若干個 HashEntry 對象鏈接起來的鏈表。一個 ConcurrentHashMap 實例中包含由若干個 Segment 對象組成的數(shù)組洋幻。
通過減小請求同一個鎖的頻率和盡量減少持有鎖的時間 郁轻,使得 ConcurrentHashMap 的并發(fā)性相對于 HashTable 和用同步包裝器包裝的 HashMap有了質(zhì)的提高。

===========================更正============================

1.上面的HashMap是基于JDK1.8之前的文留,1.8的下次分析后單獨補上好唯。

2.ArrayList擴容原理。翻看了下源碼燥翅,當調(diào)用add()方法之后骑篙,會先判斷是否存滿了,如果滿了森书,最終會調(diào)用如下方法進行擴容:

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

private void grow(int minCapacity) {
// overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

由上面可知靶端,newCapacity = oldCapacity + (oldCapacity >> 1);這個是新的容量是原來的1.5倍,即初始是10凛膏,經(jīng)過一次擴容后變?yōu)?5杨名。


本文原創(chuàng)發(fā)布于公眾號《Android面試專欄》,歡迎搜索關(guān)注猖毫!也歡迎大家留言投稿台谍!

動動手指吧 _

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吁断,隨后出現(xiàn)的幾起案子典唇,更是在濱河造成了極大的恐慌,老刑警劉巖胯府,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異恨胚,居然都是意外死亡骂因,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門赃泡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寒波,“玉大人乘盼,你說我怎么就攤上這事《硭福” “怎么了绸栅?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長页屠。 經(jīng)常有香客問我粹胯,道長,這世上最難降的妖魔是什么辰企? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任风纠,我火速辦了婚禮,結(jié)果婚禮上牢贸,老公的妹妹穿的比我還像新娘竹观。我一直安慰自己,他們只是感情好潜索,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布臭增。 她就那樣靜靜地躺著,像睡著了一般竹习。 火紅的嫁衣襯著肌膚如雪誊抛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天由驹,我揣著相機與錄音芍锚,去河邊找鬼。 笑死蔓榄,一個胖子當著我的面吹牛并炮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播甥郑,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼逃魄,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了澜搅?” 一聲冷哼從身側(cè)響起伍俘,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎勉躺,沒想到半個月后癌瘾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡饵溅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年妨退,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡咬荷,死狀恐怖冠句,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幸乒,我是刑警寧澤懦底,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站罕扎,受9級特大地震影響聚唐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜壳影,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一拱层、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宴咧,春花似錦根灯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至氧卧,卻和暖如春桃笙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背沙绝。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工搏明, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人闪檬。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓星著,卻偏偏與公主長得像,于是被迫代替她去往敵國和親粗悯。 傳聞我的和親對象是個殘疾皇子虚循,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容