這幾道Java集合框架面試題在面試中幾乎必問

Arraylist 與 LinkedList 異同

1. 是否保證線程安全:?ArrayList 和 LinkedList 都是不同步的,也就是不保證線程安全;

2. 底層數據結構:?Arraylist 底層使用的是Object數組;LinkedList 底層使用的是雙向循環鏈表數據結構;

3. 插入和刪除是否受元素位置的影響:?①?ArrayList 采用數組存儲,所以插入和刪除元素的時間復雜度受元素位置的影響。?比如:執行add(E e)方法的時候, ArrayList 會默認在將指定的元素追加到此列表的末尾,這種情況時間復雜度就是O(1)。但是如果要在指定位置 i 插入和刪除元素的話(add(int index, E element))時間復雜度就為 O(n-i)。因為在進行上述操作的時候集合中第 i 和第 i 個元素之后的(n-i)個元素都要執行向后位/向前移一位的操作。 ②?LinkedList 采用鏈表存儲,所以插入,刪除元素時間復雜度不受元素位置的影響,都是近似 O(1)而數組為近似 O(n)。

4. 是否支持快速隨機訪問:?LinkedList 不支持高效的隨機元素訪問,而ArrayList 實現了RandmoAccess 接口,所以有隨機訪問功能。快速隨機訪問就是通過元素的序號快速獲取元素對象(對應于get(int index)方法)。

5. 內存空間占用:?ArrayList的空 間浪費主要體現在在list列表的結尾會預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗比ArrayList更多的空間(因為要存放直接后繼和直接前驅以及數據)。

補充:數據結構基礎之雙向鏈表

雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數據結點中都有兩個指針,分別指向直接后繼和直接前驅。所以,從雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和后繼結點。一般我們都構造雙向循環鏈表,如下圖所示,同時下圖也是LinkedList 底層使用的是雙向循環鏈表數據結構。

ArrayList 與 Vector 區別

Vector類的所有方法都是同步的。可以由兩個線程安全地訪問一個Vector對象、但是一個線程訪問Vector的話代碼要在同步操作上耗費大量的時間。

Arraylist不是同步的,所以在不需要保證線程安全時時建議使用Arraylist。

HashMap的底層實現

JDK1.8之前

JDK1.8 之前 HashMap 由?數組+鏈表?組成的(“鏈表散列”?即數組和鏈表的結合體),數組是 HashMap 的主體,鏈表則是主要為了解決哈希沖突而存在的(HashMap 采用?“拉鏈法也就是鏈地址法”?解決沖突),如果定位到的數組位置不含鏈表(當前 entry 的 next 指向 null ),那么對于查找,添加等操作很快,僅需一次尋址即可;如果定位到的數組包含鏈表,對于添加操作,其時間復雜度依然為 O(1),因為最新的 Entry 會插入鏈表頭部,急需要簡單改變引用鏈即可,而對于查找操作來講,此時就需要遍歷鏈表,然后通過 key 對象的 equals 方法逐一比對查找.

所謂?“拉鏈法”?就是將鏈表和數組相結合。也就是說創建一個鏈表數組,數組中每一格就是一個鏈表。若遇到哈希沖突,則將沖突的值加到鏈表中即可。


我剛整理了一套2018最新的0基礎入門和進階教程,無私分享,加Java學習裙 :678-241-563 即可獲取,內附:開發工具和安裝包,以及系統學習路線圖

JDK1.8之后

相比于之前的版本, JDK1.8之后在解決哈希沖突時有了較大的變化,當鏈表長度大于閾值(默認為8)時,將鏈表轉化為紅黑樹,以減少搜索時間。

TreeMap、TreeSet以及JDK1.8之后的HashMap底層都用到了紅黑樹。紅黑樹就是為了解決二叉查找樹的缺陷,因為二叉查找樹在某些情況下會退化成一個線性結構。

HashMap 和 Hashtable 的區別

線程是否安全:?HashMap 是非線程安全的,HashTable 是線程安全的;HashTable 內部的方法基本都經過 synchronized 修飾。(如果你要保證線程安全的話就使用 ConcurrentHashMap 吧!);

效率:?因為線程安全的問題,HashMap 要比 HashTable 效率高一點。另外,HashTable 基本被淘汰,不要在代碼中使用它;

對Null key 和Null value的支持:?HashMap 中,null 可以作為鍵,這樣的鍵只有一個,可以有一個或多個鍵所對應的值為 null。。但是在 HashTable 中 put 進的鍵值只要有一個 null,直接拋出 NullPointerException。

初始容量大小和每次擴充容量大小的不同 :?①創建時如果不指定容量初始值,Hashtable 默認的初始大小為11,之后每次擴充,容量變為原來的2n+1。HashMap 默認的初始化大小為16。之后每次擴充,容量變為原來的2倍。②創建時如果給定了容量初始值,那么 Hashtable 會直接使用你給定的大小,而 HashMap 會將其擴充為2的冪次方大小。也就是說 HashMap 總是使用2的冪作為哈希表的大小,后面會介紹到為什么是2的冪次方。

底層數據結構:?JDK1.8 以后的 HashMap 在解決哈希沖突時有了較大的變化,當鏈表長度大于閾值(默認為8)時,將鏈表轉化為紅黑樹,以減少搜索時間。Hashtable 沒有這樣的機制。

HashMap 的長度為什么是2的冪次方

為了能讓 HashMap 存取高效,盡量較少碰撞,也就是要盡量把數據分配均勻,每個鏈表/紅黑樹長度大致相同。這個實現就是把數據存到哪個鏈表/紅黑樹中的算法。

這個算法應該如何設計呢?

我們首先可能會想到采用%取余的操作來實現。但是,重點來了:“取余(%)操作中如果除數是2的冪次則等價于與其除數減一的與(&)操作(也就是說 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。”?并且?采用二進制位操作 &,相對于%能夠提高運算效率,這就解釋了 HashMap 的長度為什么是2的冪次方。

HashSet 和 HashMap 區別

ConcurrentHashMap 和 Hashtable 的區別

ConcurrentHashMap 和 Hashtable 的區別主要體現在實現線程安全的方式上不同。

底層數據結構:?JDK1.7的 ConcurrentHashMap 底層采用?分段的數組+鏈表?實現,JDK1.8 采用的數據結構跟HashMap1.8的結構一樣,數組+鏈表/紅黑二叉樹。Hashtable 和 JDK1.8 之前的 HashMap 的底層數據結構類似都是采用?數組+鏈表?的形式,數組是 HashMap 的主體,鏈表則是主要為了解決哈希沖突而存在的;

實現線程安全的方式(重要):?①?在JDK1.7的時候,ConcurrentHashMap(分段鎖)?對整個桶數組進行了分割分段(Segment),每一把鎖只鎖容器其中一部分數據,多線程訪問容器里不同數據段的數據,就不會存在鎖競爭,提高并發訪問率。(默認分配16個Segment,比Hashtable效率提高16倍。)?到了 JDK1.8 的時候已經摒棄了Segment的概念,而是直接用 Node 數組+鏈表+紅黑樹的數據結構來實現,并發控制使用 synchronized 和 CAS 來操作。(JDK1.6以后 對 synchronized鎖做了很多優化)?整個看起來就像是優化過且線程安全的 HashMap,雖然在JDK1.8中還能看到 Segment 的數據結構,但是已經簡化了屬性,只是為了兼容舊版本;②?Hashtable(同一把鎖)?:使用 synchronized 來保證線程安全,效率非常低下。當一個線程訪問同步方法時,其他線程也訪問同步方法,可能會進入阻塞或輪詢狀態,如使用 put 添加元素,另一個線程不能使用 put 添加元素,也不能使用 get,競爭會越來越激烈效率越低。

HashTable:

JDK1.7的ConcurrentHashMap:

JDK1.8的ConcurrentHashMap(TreeBin: 紅黑二叉樹節點 Node: 鏈表節點):

ConcurrentHashMap線程安全的具體實現方式/底層具體實現

JDK1.7(上面有示意圖)

首先將數據分為一段一段的存儲,然后給每一段數據配一把鎖,當一個線程占用鎖訪問其中一個段數據時,其他段的數據也能被其他線程訪問。

ConcurrentHashMap 是由 Segment 數組結構和 HahEntry 數組結構組成

Segment 實現了 ReentrantLock,所以 Segment 是一種可重入鎖,扮演鎖的角色。HashEntry 用于存儲鍵值對數據。

static class Segment extends ReentrantLock implements Serializable {

}

一個 ConcurrentHashMap 里包含一個 Segment 數組。Segment 的結構和HashMap類似,是一種數組和鏈表結構,一個 Segment 包含一個 HashEntry 數組,每個 HashEntry 是一個鏈表結構的元素,每個 Segment 守護著一個HashEntry數組里的元素,當對 HashEntry 數組的數據進行修改時,必須首先獲得對應的 Segment的鎖。

JDK1.8?(上面有示意圖)

ConcurrentHashMap取消了Segment分段鎖,采用CAS和synchronized來保證并發安全。數據結構跟HashMap1.8的結構類似,數組+鏈表/紅黑二叉樹。

synchronized只鎖定當前鏈表或紅黑二叉樹的首節點,這樣只要hash不沖突,就不會產生并發,效率又提升N倍。

集合框架底層數據結構總結

Collection

1. List

Arraylist:?Object數組

Vector:?Object數組

LinkedList:?雙向循環鏈表

2. Set

HashSet(無序,唯一):?基于 HashMap 實現的,底層采用 HashMap 來保存元素

LinkedHashSet:?LinkedHashSet 繼承與 HashSet,并且其內部是通過 LinkedHashMap 來實現的。有點類似于我們之前說的LinkedHashMap 其內部是基于 Hashmap 實現一樣,不過還是有一點點區別的。

TreeSet(有序,唯一):?紅黑樹(自平衡的排序二叉樹。)

Map

HashMap:?JDK1.8之前HashMap由數組+鏈表組成的,數組是HashMap的主體,鏈表則是主要為了解決哈希沖突而存在的(“拉鏈法”解決沖突).JDK1.8以后在解決哈希沖突時有了較大的變化,當鏈表長度大于閾值(默認為8)時,將鏈表轉化為紅黑樹,以減少搜索時間

LinkedHashMap:?LinkedHashMap 繼承自 HashMap,所以它的底層仍然是基于拉鏈式散列結構即由數組和鏈表或紅黑樹組成。另外,LinkedHashMap 在上面結構的基礎上,增加了一條雙向鏈表,使得上面的結構可以保持鍵值對的插入順序。同時通過對鏈表進行相應的操作,實現了訪問順序相關邏輯。詳細可以查看:《LinkedHashMap 源碼詳細分析(JDK1.8)》

HashTable:?數組+鏈表組成的,數組是 HashMap 的主體,鏈表則是主要為了解決哈希沖突而存在的

TreeMap:?紅黑樹(自平衡的排序二叉樹)

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容

  • Java SE 基礎: 封裝、繼承、多態 封裝: 概念:就是把對象的屬性和操作(或服務)結合為一個獨立的整體,并盡...
    Jayden_Cao閱讀 2,125評論 0 8
  • ArrayList實現原理要點概括 參考文獻:http://zhangshixi.iteye.com/blog/6...
    晨光光閱讀 1,087評論 0 1
  • 遇到過許多長不大的同齡人,不知道什么時候開始,小破孩兒這個稱呼出現在他身上。他總是一副天真無邪的模樣,倒顯得我們這...
    伽藍堂閱讀 368評論 0 0
  • 離開了家鄉,才知道家鄉的好。以前總是一直想要出去,離開了,發現一切不是想象中的那樣,什么都不適應,生活習慣,...
    盜夢樹洞閱讀 345評論 0 12
  • 火辣辣的六月即將到來,陪伴了三年的小妖精們即將畢業,如唐長老般啰啰嗦嗦的我卻對你們萬般不舍。三年前的我,絕不會預料...
    N8閱讀 170評論 0 0