Java集合容器面試題(2022最新版)
阿新 • • 發佈:2022-05-10
Java集合容器面試題(2022最新版)
常用的集合類有哪些?
Map介面和Collection介面是所有集合框架的父介面:
Collection介面的子介面包括:Set介面和List介面
Map介面的實現類主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及Properties等
Set介面的實現類主要有:HashSet、TreeSet、LinkedHashSet等
List介面的實現類主要有:ArrayList、LinkedList、Stack以及Vector等
List,Set,Map三者的區別?List、Set、Map 是否繼承自 Collection 介面?List、Map、Set 三個介面存取元素時,各有什麼特點?
Java 容器分為 Collection 和 Map 兩大類,Collection集合的子介面有Set、List、Queue三種子介面。我們比較常用的是Set、List,Map介面不是collection的子介面。 Collection集合主要有List和Set兩大介面 List:一個有序(元素存入集合的順序和取出的順序一致)容器,元素可以重複,可以插入多個null元素,元素都有索引。常用的實現類有 ArrayList、LinkedList 和 Vector。 Set:一個無序(存入和取出順序有可能不一致)容器,不可以儲存重複元素,只允許存入一個null元素,必須保證元素唯一性。Set 介面常用實現類是 HashSet、LinkedHashSet 以及 TreeSet。 Map是一個鍵值對集合,儲存鍵、值和之間的對映。 Key無序,唯一;value 不要求有序,允許重複。Map沒有繼承於Collection介面,從Map集合中檢索元素時,只要給出鍵物件,就會返回對應的值物件。 Map 的常用實現類:HashMap、TreeMap、HashTable、LinkedHashMap、ConcurrentHashMap
集合框架底層資料結構
Collection List Arraylist: Object陣列 Vector: Object陣列 LinkedList: 雙向迴圈連結串列 Set HashSet(無序,唯一):基於 HashMap 實現的,底層採用 HashMap 來儲存元素 LinkedHashSet: LinkedHashSet 繼承與 HashSet,並且其內部是通過 LinkedHashMap 來實現的。有點類似於我們之前說的LinkedHashMap 其內部是基於 Hashmap 實現一樣,不過還是有一點點區別的。 TreeSet(有序,唯一): 紅黑樹(自平衡的排序二叉樹。) Map HashMap: JDK1.8之前HashMap由陣列+連結串列組成的,陣列是HashMap的主體,連結串列則是主要為了解決雜湊衝突而存在的(“拉鍊法”解決衝突).JDK1.8以後在解決雜湊衝突時有了較大的變化,當連結串列長度大於閾值(預設為8)時,將連結串列轉化為紅黑樹,以減少搜尋時間 LinkedHashMap:LinkedHashMap 繼承自 HashMap,所以它的底層仍然是基於拉鍊式雜湊結構即由陣列和連結串列或紅黑樹組成。另外,LinkedHashMap 在上面結構的基礎上,增加了一條雙向連結串列,使得上面的結構可以保持鍵值對的插入順序。同時通過對連結串列進行相應的操作,實現了訪問順序相關邏輯。 HashTable: 陣列+連結串列組成的,陣列是 HashMap 的主體,連結串列則是主要為了解決雜湊衝突而存在的 TreeMap: 紅黑樹(自平衡的排序二叉樹)
哪些集合類是執行緒安全
vector:就比arraylist多了個同步化機制(執行緒安全),因為效率較低,現在已經不太建議使用。在web應用中,特別是前臺頁面,往往效率(頁面響應速度)是優先考慮的。
statck:堆疊類,先進後出。
hashtable:就比hashmap多了個執行緒安全。
enumeration:列舉,相當於迭代器。
Java集合的快速失敗機制 “fail-fast”?
是java集合的一種錯誤檢測機制,當多個執行緒對集合進行結構上的改變的操作時,有可能會產生 fail-fast 機制。
例如:假設存在兩個執行緒(執行緒1、執行緒2),執行緒1通過Iterator在遍歷集合A中的元素,在某個時候執行緒2修改了集合A的結構(是結構上面的修改,而不是簡單的修改集合元素的內容),那麼這個時候程式就會丟擲 ConcurrentModificationException 異常,從而產生fail-fast機制。
原因:迭代器在遍歷時直接訪問集合中的內容,並且在遍歷過程中使用一個 modCount 變數。集合在被遍歷期間如果內容發生變化,就會改變modCount的值。每當迭代器使用hashNext()/next()遍歷下一個元素之前,都會檢測modCount變數是否為expectedmodCount值,是的話就返回遍歷;否則丟擲異常,終止遍歷。
解決辦法:
1.在遍歷過程中,所有涉及到改變modCount值得地方全部加上synchronized。
2.使用CopyOnWriteArrayList來替換ArrayList
怎麼確保一個集合不能被修改?
可以使用 Collections. unmodifiableCollection(Collection c) 方法來建立一個只讀集合,這樣改變集合的任何操作都會丟擲 Java. lang. UnsupportedOperationException 異常。
Iterator 和 ListIterator 有什麼區別?
Iterator 可以遍歷 Set 和 List 集合,而 ListIterator 只能遍歷 List。
Iterator 只能單向遍歷,而 ListIterator 可以雙向遍歷(向前/後遍歷)。
ListIterator 實現 Iterator 介面,然後添加了一些額外的功能,比如新增一個元素、替換一個元素、獲取前面或後面元素的索引位置。
遍歷一個 List 有哪些不同的方式?每種方法的實現原理是什麼?Java 中 List 遍歷的最佳實踐是什麼?
遍歷方式有以下幾種:
for 迴圈遍歷,基於計數器。在集合外部維護一個計數器,然後依次讀取每一個位置的元素,當讀取到最後一個元素後停止。
迭代器遍歷,Iterator。Iterator 是面向物件的一個設計模式,目的是遮蔽不同資料集合的特點,統一遍歷集合的介面。Java 在 Collections 中支援了 Iterator 模式。
foreach 迴圈遍歷。foreach 內部也是採用了 Iterator 的方式實現,使用時不需要顯式宣告 Iterator 或計數器。優點是程式碼簡潔,不易出錯;缺點是隻能做簡單的遍歷,不能在遍歷過程中操作資料集合,例如刪除、替換。
最佳實踐:Java Collections 框架中提供了一個 RandomAccess 介面,用來標記 List 實現是否支援 Random Access。
如果一個數據集合實現了該介面,就意味著它支援 Random Access,按位置讀取元素的平均時間複雜度為 O(1),如ArrayList。
如果沒有實現該介面,表示不支援 Random Access,如LinkedList。
推薦的做法就是,支援 Random Access 的列表可用 for 迴圈遍歷,否則建議用 Iterator 或 foreach 遍歷。
說一下 ArrayList 的優缺點
ArrayList的優點如下:
ArrayList 底層以陣列實現,是一種隨機訪問模式。ArrayList 實現了 RandomAccess 介面,因此查詢的時候非常快。
ArrayList 在順序新增一個元素的時候非常方便。
ArrayList 的缺點如下:
刪除元素的時候,需要做一次元素複製操作。如果要複製的元素很多,那麼就會比較耗費效能。
插入元素的時候,也需要做一次元素複製操作,缺點同上。
ArrayList 比較適合順序新增、隨機訪問的場景。
ArrayList 和 LinkedList 的區別是什麼?
資料結構實現:ArrayList 是動態陣列的資料結構實現,而 LinkedList 是雙向連結串列的資料結構實現。
隨機訪問效率:ArrayList 比 LinkedList 在隨機訪問的時候效率要高,因為 LinkedList 是線性的資料儲存方式,所以需要移動指標從前往後依次查詢。
增加和刪除效率:在非首尾的增加和刪除操作,LinkedList 要比 ArrayList 效率要高,因為 ArrayList 增刪操作要影響陣列內的其他資料的下標。
記憶體空間佔用:LinkedList 比 ArrayList 更佔記憶體,因為 LinkedList 的節點除了儲存資料,還儲存了兩個引用,一個指向前一個元素,一個指向後一個元素。
執行緒安全:ArrayList 和 LinkedList 都是不同步的,也就是不保證執行緒安全;
綜合來說,在需要頻繁讀取集合中的元素時,更推薦使用 ArrayList,而在插入和刪除操作較多時,更推薦使用 LinkedList。
List 和 Set 的區別
List , Set 都是繼承自Collection 介面
List 特點:一個有序(元素存入集合的順序和取出的順序一致)容器,元素可以重複,可以插入多個null元素,元素都有索引。常用的實現類有 ArrayList、LinkedList 和 Vector。
Set 特點:一個無序(存入和取出順序有可能不一致)容器,不可以儲存重複元素,只允許存入一個null元素,必須保證元素唯一性。Set 介面常用實現類是 HashSet、LinkedHashSet 以及 TreeSet。
另外 List 支援for迴圈,也就是通過下標來遍歷,也可以用迭代器,但是set只能用迭代,因為他無序,無法用下標來取得想要的值。
Set和List對比
Set:檢索元素效率低下,刪除和插入效率高,插入和刪除不會引起元素位置改變。
List:和陣列類似,List可以動態增長,查詢元素效率高,插入刪除元素效率低,因為會引起其他元素位置改變
說一下 HashSet 的實現原理?
HashSet 是基於 HashMap 實現的,HashSet的值存放於HashMap的key上,HashMap的value統一為PRESENT,因此 HashSet 的實現比較簡單,相關 HashSet 的操作,基本上都是直接呼叫底層 HashMap 的相關方法來完成,HashSet 不允許重複的值。
HashSet如何檢查重複?HashSet是如何保證資料不可重複的?
向HashSet 中add ()元素時,判斷元素是否存在的依據,不僅要比較hash值,同時還要結合equles 方法比較。
HashSet 中的add ()方法會使用HashMap 的put()方法。
HashMap 的 key 是唯一的,由原始碼可以看出 HashSet 新增進去的值就是作為HashMap 的key,並且在HashMap中如果K/V相同時,會用新的V覆蓋掉舊的V,然後返回舊的V。所以不會重複( HashMap 比較key是否相等是先比較hashcode 再比較equals )。
BlockingQueue是什麼?
Java.util.concurrent.BlockingQueue是一個佇列,在進行檢索或移除一個元素的時候,它會等待佇列變為非空;當在新增一個元素時,它會等待佇列中的可用空間。BlockingQueue介面是Java集合框架的一部分,主要用於實現生產者-消費者模式。我們不需要擔心等待生產者有可用的空間,或消費者有可用的物件,因為它都在BlockingQueue的實現類中被處理了。Java提供了集中BlockingQueue的實現,比如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue,、SynchronousQueue等。
在 Queue 中 poll()和 remove()有什麼區別?
相同點:都是返回第一個元素,並在佇列中刪除返回的物件。
不同點:如果沒有元素 poll()會返回 null,而 remove()會直接丟擲 NoSuchElementException 異常。
說一下 HashMap 的實現原理?
HashMap概述: HashMap是基於雜湊表的Map介面的非同步實現。此實現提供所有可選的對映操作,並允許使用null值和null鍵。此類不保證對映的順序,特別是它不保證該順序恆久不變。
HashMap的資料結構: 在Java程式語言中,最基本的結構就是兩種,一個是陣列,另外一個是模擬指標(引用),所有的資料結構都可以用這兩個基本結構來構造的,HashMap也不例外。HashMap實際上是一個“連結串列雜湊”的資料結構,即陣列和連結串列的結合體。
HashMap 基於 Hash 演算法實現的
當我們往Hashmap中put元素時,利用key的hashCode重新hash計算出當前物件的元素在陣列中的下標
儲存時,如果出現hash值相同的key,此時有兩種情況。(1)如果key相同,則覆蓋原始值;(2)如果key不同(出現衝突),則將當前的key-value放入連結串列中
獲取時,直接找到hash值對應的下標,在進一步判斷key是否相同,從而找到對應值。
理解了以上過程就不難明白HashMap是如何解決hash衝突的問題,核心就是使用了陣列的儲存方式,然後將衝突的key的物件放入連結串列中,一旦發現衝突就在連結串列中做進一步的對比。