備戰詳解22道Java面試常問集合框架面試真題,讓面試官無話可說!

備戰詳解22道Java面試常問集合框架面試真題,讓面試官無話可說!

簡介

集合框架:用於存儲數據的容器。

集合框架是爲表示和操作集合而規定的一種統一的標準的體系結構。

任何集合框架都包含三大塊內容:對外的接口、接口的實現和對集合運算的算法。

  • 接口:表示集合的抽象數據類型。接口允許我們操作集合時不必關注具體實現,從而達到“多態”。在面向對象編程語言中,接口通常用來形成規範。

  • 實現:集合接口的具體實現,是重用性很高的數據結構。

  • 算法:在一個實現了某個集合框架中的接口的對象身上完成某種有用的計算的方法,例如查找、排序等。這些算法通常是多態的,因爲相同的方法可以在同一個接口被多個類實現時有不同的表現。事實上,算法是可複用的函數。

它減少了程序設計的辛勞。

集合框架通過提供有用的數據結構和算法使你能集中注意力於你的程序的重要部分上,而不是爲了讓程序能正常運轉而將注意力於低層設計上。

通過這些在無關API之間的簡易的互用性,使你免除了爲改編對象或轉換代碼以便聯合這些API而去寫大量的代碼。它提高了程序速度和質量。

Java 集合框架圖如下:

備戰詳解22道Java面試常問集合框架面試真題,讓面試官無話可說!

面試解析

1.ArrayList 和 Vector 的區別。

這兩個類都實現了 List 接口(List 接口繼承了 Collection 接口),他們都是有序集合,即存儲在這兩個集合中的元素的位置都是有順序的,相當於一種動態的數組,我們以後可以按位置索引號取出某個元素,並且其中的數據是允許重複的,這是HashSet 之類的集合的最大不同處,HashSet 之類的集合不可以按索引號去檢索其中的元素,也不允許有重複的元素(本來題目問的與 hashset 沒有任何關係,但爲了說清楚ArrayList 與 Vector 的功能,我們使用對比方式,更有利於說明問題)。接着才說 ArrayList 與 Vector 的區別,這主要包括兩個方面。

  • 同步性:

Vector 是線程安全的,也就是說是它的方法之間是線程同步的,而 ArrayList 是線程序不安全的,它的方法之間是線程不同步的。如果只有一個線程會訪問到集合,那最好是使用 ArrayList,因爲它不考慮線程安全,效率會高些;如果有多個線程會訪問到集合,那最好是使用 Vector,因爲不需要我們自己再去考慮和編寫線程安全的代碼。

備註:對於 Vector&ArrayList、Hashtable&HashMap,要記住線程安全的問題,記住 Vector 與 Hashtable 是舊的,是 java 一誕生就提供了的,它們是線程安全的,ArrayList 與 HashMap 是 java2 時才提供的,它們是線程不安全的。

  • 數據增長:

ArrayList 與 Vector 都有一個初始的容量大小,當存儲進它們裏面的元素的個數超過了容量時,就需要增加 ArrayList 與 Vector 的存儲空間,每次要增加存儲空間時,不是隻增加一個存儲單元,而是增加多個存儲單元,每次增加的存儲單元的個數在內存空間利用與程序效率之間要取得一定的平衡。Vector 默認增長爲原來兩倍,而ArrayList 的增長策略在文檔中沒有明確規定(從源代碼看到的是增長爲原來的 1.5倍)。

ArrayList 與 Vector 都可以設置初始的空間大小,Vector 還可以設置增長的空間大小,而 ArrayList 沒有提供設置增長空間的方法。

總結:即 Vector 增長原來的一倍,ArrayList 增加原來的 0.5 倍。

2.說說 ArrayList,Vector, LinkedList 的存儲性能和特性。

ArrayList 和 Vector 都是使用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及數組元素移動等內存操作,所以索引數據快而插入數據慢,Vector 由於使用了synchronized 方法(線程安全)。

通常性能上較 ArrayList 差,而 LinkedList 使用雙向鏈表實現存儲,按序號索引數據需要進行前向或後向遍歷,但是插入數據時只需要記錄本項的前後項即可,所以插入速度較快 。

ArrayList 在查找時速度快,LinkedList 在插入與刪除時更具優勢。

3.快速失敗 (fail-fast) 和安全失敗 (fail-safe) 的區別是什麼?

Iterator 的安全失敗是基於對底層集合做拷貝,因此,它不受源集合上修改的影響。java.util 包下面的所有的集合類都是快速失敗的,而 java.util.concurrent 包下面的所有的類都是安全失敗的。快速失敗的迭代器會拋出ConcurrentModificationException 異常,而安全失敗的迭代器永遠不會拋出這樣的異常。

4.hashmap 的數據結構

在 java 編程語言中,最基本的結構就是兩種,一個是數組,另外一個是模擬指針(引用),所有的數據結構都可以用這兩個基本結構來構造的,hashmap 也不例外。
Hashmap 實際上是一個數組和鏈表的結合體(在數據結構中,一般稱之爲 “鏈表散列 “)

備戰詳解22道Java面試常問集合框架面試真題,讓面試官無話可說!

5.HashMap 的工作原理是什麼?

Java 中的 HashMap 是以鍵值對 (key-value) 的形式存儲元素的。HashMap 需要一個 hash 函數,它使用 hashCode()和 equals()方法來向集合 / 從集合添加和檢索元素。

當調用 put() 方法的時候,HashMap 會計算 key 的 hash 值,然後把鍵值對存儲在集合中合適的索引上。

如果 key 已經存在了,value 會被更新成新值。HashMap 的一些重要的特性是它的容量 (capacity),負載因子 (load factor) 和擴容極限(threshold resizing)。

6.Hashmap 什麼時候進行擴容呢?

當 hashmap 中的元素個數超過數組大小 loadFactor 時,就會進行數組擴容,loadFactor 的默認值爲 0.75,也就是說,默認情況下,數組大小爲 16,那麼當hashmap 中元素個數超過 160.75=12 的時候,就把數組的大小擴展爲 216=32,即擴大一倍,然後重新計算每個元素在數組中的位置,而這是一個非常消耗性能的操作,

所以如果我們已經預知 hashmap 中元素的個數,那麼預設元素的個數能夠有效的提高 hashmap 的性能。比如說,我們有 1000 個元素 new HashMap(1000),但是理論上來講 new HashMap(1024) 更合適,不過上面 annegu 已經說過,即使是 1000,hashmap 也自動會將其設置爲 1024。 但是 new HashMap(1024) 還不是更合適的,因爲 0.751000 < 1000, 也就是說爲了讓 0.75 size > 1000, 我們必須這樣newHashMap(2048) 才最合適,既考慮了 & 的問題,也避免了 resize的問題。

7.List、Map、Set 三個接口,存取元素時,各有什麼特點?

首先,List 與 Set 具有相似性,它們都是單列元素的集合,所以,它們有一個功共同的父接口,叫 Collection。Set 裏面不允許有重複的元素,所謂重複,即不能有兩個相等(注意,不是僅僅是相同)的對象 ,即假設 Set 集合中有了一個 A 對象,現在我要向 Set 集合再存入一個 B 對象,但 B 對象與 A 對象 equals 相等,則 B 對象存儲不進去,所以,Set 集合的 add 方法有一個 boolean 的返回值,當集合中沒有某個元素,此時 add 方法可成功加入該元素時,則返回 true,當集合含有與某個元素 equals 相等的元素時,此時 add 方法無法加入該元素,返回結果爲 false。Set 取元素時,沒法說取第幾個,只能以 Iterator 接口取得所有的元素,再逐一遍歷各個元素。

List 表示有先後順序的集合, 注意,不是那種按年齡、按大小、按價格之類的排序。當我們多次調用 add(Obj e) 方法時,每次加入的對象就像火車站買票有排隊順序一樣,按先來後到的順序排序。有時候,也可以插隊,即調用 add(int index,Obj e) 方法,就可以指定當前對象在集合中的存放位置。一個對象可以被反覆存儲進 List 中,每調用一次 add 方法,這個對象就被插入進集合中一次,其實,並不是把這個對象本身存儲進了集合中,而是在集合中用一個索引變量指向這個對象,當這個對象被add 多次時,即相當於集合中有多個索引指向了這個對象,如圖 x 所示。List 除了可以以 Iterator 接口取得所有的元素,再逐一遍歷各個元素之外,還可以調用get(index i) 來明確說明取第幾個。

Map 與 List 和 Set 不同,它是雙列的集合,其中有 put 方法,定義如下:put(obj key,obj value),每次存儲時,要存儲一對 key/value,不能存儲重複的key,這個重複的規則也是按 equals 比較相等。取則可以根據 key 獲得相應的value,即 get(Object key) 返回值爲 key 所對應的 value。另外,也可以獲得所有的 key 的結合,還可以獲得所有的 value 的結合,還可以獲得 key 和 value 組合成的 Map.Entry 對象的集合。

List 以特定次序來持有元素,可有重複元素。Set 無法擁有重複元素, 內部排序。Map 保存 key-value 值,value 可多值。

HashSet 按照 hashcode 值的某種運算方式進行存儲,而不是直接按 hashCode值的大小進行存儲。例如,"abc" ---> 78,"def" ---> 62,"xyz" ---> 65 在hashSet 中的存儲順序不是 62,65,78,這些問題感謝以前一個叫崔健的學員提出,最後通過查看源代碼給他解釋清楚,看本次培訓學員當中有多少能看懂源碼。LinkedHashSet 按插入的順序存儲,那被存儲對象的 hashcode 方法還有什麼作用呢?學員想想! hashset 集合比較兩個對象是否相等,首先看 hashcode 方法是否相等,然後看 equals 方法是否相等。new 兩個 Student 插入到 HashSet 中,看HashSet 的 size,實現 hashcode 和 equals 方法後再看 size。

同一個對象可以在 Vector 中加入多次。往集合裏面加元素,相當於集合裏用一根繩子連接到了目標對象。往 HashSet 中卻加不了多次的。

8.Set 裏的元素是不能重複的,那麼用什麼方法來區分重複與否呢? 是用 == 還是equals()? 它們有何區別?

Set 裏的元素是不能重複的,元素重複與否是使用 equals() 方法進行判斷的。

equals() 和 == 方法決定引用值是否指向同一對象 equals() 在類中被覆蓋,爲的是當兩個分離的對象的內容和類型相配的話,返回真值。

9.兩個對象值相同 (x.equals(y) == true),但卻可有不同的 hash code,這句話對不對?

對。如果對象要保存在 HashSet 或 HashMap 中,它們的 equals 相等,那麼,它們的 hashcode 值就必須相等。

如果不是要保存在 HashSet 或 HashMap,則與 hashcode 沒有什麼關係了,這時候 hashcode 不等是可以的,例如 arrayList 存儲的對象就不用實現 hashcode,當然,我們沒有理由不實現,通常都會去實現的。

10.heap 和 stack 有什麼區別。

Java 的內存分爲兩類:

  • 一類是棧內存
  • 一類是堆內存。

棧內存是指程序進入一個方法時,會爲這個方法單獨分配一塊私屬存儲空間,用於存儲這個方法內部的局部變量,當這個方法結束時,分配給這個方法的棧會釋放,這個棧中的變量也將隨之釋放。

堆是與棧作用不同的內存,一般用於存放不放在當前方法棧中的那些數據,例如,使用 new 創建的對象都放在堆裏,所以,它不會隨方法的結束而消失。方法中的局部變量使用 final 修飾後,放在堆中,而不是棧中。

備戰詳解22道Java面試常問集合框架面試真題,讓面試官無話可說!

11.Java 集合類框架的基本接口有哪些?

集合類接口指定了一組叫做元素的對象。集合類接口的每一種具體的實現類都可以選擇以它 自己的方式對元素進行保存和排序。有的集合類允許重複的鍵,有些不允許。

Java 集合類提供了一套設計良好的支持對一組對象進行操作的接口和類。Java 集合類裏面 最基本的接口有:

  • Collection:代表一組對象,每一個對象都是它的子元素。
  • Set:不包含重複元素的 Collection。
  • List:有順序的 collection,並且可以包含重複元素。
  • Map:可以把鍵 (key) 映射到值 (value) 的對象,鍵不能重複。

12.HashSet 和 TreeSet 有什麼區別?

  • HashSet 是由一個 hash 表來實現的,因此,它的元素是無序的。add(),remove(),contains()

  • TreeSet 是由一個樹形的結構來實現的,它裏面的元素是有序的。因此,add(),remove(),contains() 方法的時間複雜度是 O(logn)。

13.HashSet 的底層實現是什麼?

通過看源碼知道 HashSet 的實現是依賴於 HashMap 的,HashSet 的值都是存儲在 HashMap 中的。在 HashSet 的構造法中會初始化一個 HashMap 對象,HashSet 不允許值重複,因此,HashSet 的值是作爲HashMap 的 key 存儲在HashMap 中的,當存儲的值已經存在時返回 false。

14.LinkedHashMap 的實現原理?

LinkedHashMap 也是基於 HashMap 實現的,不同的是它定義了一個 Entryheader,這個 header 不是放在 Table 裏,它是額外獨立出來的。

LinkedHashMap 通過繼承 hashMap 中的 Entry, 並添加兩個屬性 Entrybefore,after, 和 header 結合起來組成一個雙向鏈表,來實現按插入順序或訪問順序排序。

LinkedHashMap 定義了排序模式 accessOrder,該屬性爲 boolean 型變量,對於訪問順序,爲 true;對於插入順序,則爲 false。一般情況下,不必指定排序模式,其迭代順序即爲默認爲插入順序。

15.爲什麼集合類沒有實現 Cloneable 和 Serializable 接口?

克隆 (cloning) 或者是序列化 (serialization) 的語義和含義是跟具體的實現相關的。因此,應該 由集合類的具體實現來決定如何被克隆或者是序列化。

16.什麼是迭代器 (Iterator)?

Iterator 接口提供了很多對集合元素進行迭代的方法。每一個集合類都包含了可以返回迭代 器實例的迭代方法。迭代器可以在迭代的過程中刪除底層集合的元素, 但是不可以直接調用集合的 remove(Object Obj) 刪除,可以通過迭代器的 remove() 方法刪除。

17.Iterator 和 ListIterator 的區別是什麼?

下面列出了他們的區別:

  • Iterator 可用來遍歷 Set 和 List 集合,但是 ListIterator 只能用來遍歷 List。
  • Iterator 對集合只能是前向遍歷,ListIterator 既可以前向也可以後向。

ListIterator 實現了 Iterator 接口,幷包含其他的功能,比如:增加元素,替換元素,獲取前一個和後一個元素的索引,等等。

18.數組 (Array) 和列表 (ArrayList) 有什麼區別?什麼時候應該使用 Array 而不是ArrayList?

  • Array 可以包含基本類型和對象類型,ArrayList 只能包含對象類型。
  • Array 大小是固定的,ArrayList 的大小是動態變化的。

ArrayList 處理固定大小的基本數據類型的時候,這種方式相對比較慢。

19.Java 集合類框架的最佳實踐有哪些?

  • 假如元素的大小是固 定的,而且能事先知道,我們就應該用 Array 而不是ArrayList。

  • 有些集合類允許指定初始容量。因此,如果我們能估計出存儲的元素的數目,我們可以設置 初始容量來避免重新計算 hash 值或者是擴容。

  • 爲了類型安全,可讀性和健壯性的原因總是要使用泛型。同時,使用泛型還可以避免運行時的 ClassCastException。

  • 使用 JDK 提供的不變類 (immutable class) 作爲 Map 的鍵可以避免爲我們自己的類實現 hashCode()和 equals()方法。

  • 編程的時候接口優於實現。

  • 底層的集合實際上是空的情況下,返回長度是 0 的集合或者是數組,不要返回 null。

20.Set 裏的元素是不能重複的,那麼用什麼方法來區分重複與否呢?是用 == 還是equals()?它們有何區別?

Set 裏的元素是不能重複的,那麼用 iterator() 方法來區分重複與否。equals() 是判讀兩個 Set 是否相等

equals() 和 == 方法決定引用值是否指向同一對象 equals() 在類中被覆蓋,爲的是當兩個分離的對象的內容和類型相配的話,返回真值

21.Comparable 和 Comparator 接口是幹什麼的?列出它們的區別

Java 提供了只包含一個 compareTo() 方法的 Comparable 接口。這個方法可以個給兩個對象排序。具體來說,它返回負數,0,正數來表明輸入對象小於,等於,大於已經存在的對象。

Java 提供了包含 compare() 和 equals() 兩個方法的 Comparator 接口。

compare() 方法用來給兩個輸入參數排序,返回負數,0,正數表明第一個參數是小於,等於,大於第二個參數。equals() 方法需要一個對象作爲參數,它用來決定輸入參數是否和 comparator 相等。只有當輸入參數也是一個 comparator 並且輸入參數和當前 comparator 的排序結果是相同的時 候,這個方法才返回 true。

22.Collection 和 Collections 的區別

  • collection 是集合類的上級接口, 繼承與它的接口主要是 set 和 list。
  • collections 類是針對集合類的一個幫助類. 它提供一系列的靜態方法對各種集合的搜索, 排序, 線程安全化等操作。

備戰詳解22道Java面試常問集合框架面試真題,讓面試官無話可說!

現在很多程序員,都會陷入到一個怪圈:看到別人升職加薪,又覺得爲啥別人運氣總是那麼好,我和他差不多時間進公司的啊!然後去跳槽,發現,現在的面試這麼難的嘛,動不動就底層原理,動不動就源碼分析,Java不好做了,做Java的人太多了,我還是轉行吧。

歸總到一點,就是沒從自己思考,從身上找原因。無論對於程序員來說,還是對於其他崗位,想要漲薪升職,自己的能力肯定要跟得上,而唯一的辦法就是通過學習來提升自己。

廢話也不多說,我自己分享一下我自己的一套學習資料庫,大夥看看有沒有需要的:

  • Java核心知識點:

備戰詳解22道Java面試常問集合框架面試真題,讓面試官無話可說!

  • Java千道面試寶典:

內容涵蓋:Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、Redis、MySQL、Spring、Spring Boot、Spring Cloud、RabbitMQ、Kafka、Linux 等技術棧

備戰詳解22道Java面試常問集合框架面試真題,讓面試官無話可說!

  • 架構學習資料:

備戰詳解22道Java面試常問集合框架面試真題,讓面試官無話可說!

  • 學習視頻:

備戰詳解22道Java面試常問集合框架面試真題,讓面試官無話可說!

以上這些學習資料都能夠免費分享給小夥伴們,希望能一起努力,共同進步!有需要的,關注我的公衆號【風平浪靜如碼】獲取!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章