Java集合/泛型面試題(含答案)

1、ArrayList和linkedList的區別

Array(數組)是基於索引(index)的數據結構,它使用索引在數組中搜索和讀取數據是很快的。
Array獲取數據的時間複雜度是O(1),但是要刪除數據卻是開銷很大,因爲這需要重排數組中的所有數據, (因爲刪除數據以後, 需要把後面所有的數據前移)
缺點: 數組初始化必須指定初始化的長度, 否則報錯
例如:
在這裏插入圖片描述
List—是一個有序的集合,可以包含重複的元素,提供了按索引訪問的方式,它繼承Collection。
List有兩個重要的實現類:ArrayList和LinkedList
ArrayList: 可以看作是能夠自動增長容量的數組
ArrayList的toArray方法返回一個數組
ArrayList的asList方法返回一個列表
ArrayList底層的實現是Array, 數組擴容實現
LinkList是一個雙鏈表,在添加和刪除元素時具有比ArrayList更好的性能.但在get與set方面弱於ArrayList.當然,這些對比都是指數據量很大或者操作很頻繁。

2、 HashMap和HashTable的區別

1、兩者父類不同
HashMap是繼承自AbstractMap類,而Hashtable是繼承自Dictionary類。不過它們都實現了同時實現了map、Cloneable(可複製)、Serializable(可序列化)這三個接口。
2、對外提供的接口不同
Hashtable比HashMap多提供了elments() 和contains() 兩個方法。
elments() 方法繼承自Hashtable的父類Dictionnary。elements() 方法用於返回此Hashtable中的value的枚舉。
contains()方法判斷該Hashtable是否包含傳入的value。它的作用與containsValue()一致。事實上,contansValue() 就只是調用了一下contains() 方法。
3、對null的支持不同
Hashtable:key和value都不能爲null。
HashMap:key可以爲null,但是這樣的key只能有一個,因爲必須保證key的唯一性;可以有多個key值對應的value爲null。
4、安全性不同
HashMap是線程不安全的,在多線程併發的環境下,可能會產生死鎖等問題,因此需要開發人員自己處理多線程的安全問題。
Hashtable是線程安全的,它的每個方法上都有synchronized 關鍵字,因此可直接用於多線程中。雖然HashMap是線程不安全的,但是它的效率遠遠高於Hashtable,這樣設計是合理的,因爲大部分的使用場景都是單線程。當需要多線程操作的時候可以使用線程安全的ConcurrentHashMap。
ConcurrentHashMap雖然也是線程安全的,但是它的效率比Hashtable要高好多倍。因爲ConcurrentHashMap使用了分段鎖,並不對整個數據進行鎖定。
5、初始容量大小和每次擴充容量大小不同
6、計算hash值的方法不同

3、Collection包結構,與Collections的區別

Collection是集合類的上級接口,子接口有 Set、List、LinkedList、ArrayList、Vector、Stack、Set;Collections是集合類的一個幫助類, 它包含有各種有關集合操作的靜態多態方法,用於實現對各種集合的搜索、排序、線程安全化等操作。此類不能實例化,就像一個工具類,服務於Java的Collection框架。

4、泛型常用特點 (待補充)

泛型是Java SE 1.5之後的特性, 《Java 核心技術》中對泛型的定義是:“泛型” 意味着編寫的代碼可以被不同類型的對象所重用。
“泛型”,顧名思義,“泛指的類型”。我們提供了泛指的概念,但具體執行的時候卻可以有具體的規則來約束,比如我們用的非常多的ArrayList就是個泛型類,ArrayList作爲集合可以存放各種元素,如Integer, String,自定義的各種類型等,但在我們使用的時候通過具體的規則來約束,如我們可以約束集合中只存放Integer類型的元素,如在這裏插入圖片描述
使用泛型的好處?
以集合來舉例,使用泛型的好處是我們不必因爲添加元素類型的不同而定義不同類型的集合,如整型集合類,浮點型集合類,字符串集合類,我們可以定義一個集合來存放整型、浮點型,字符串型數據,而這並不是最重要的,因爲我們只要把底層存儲設置了Object即可,添加的數據全部都可向上轉型爲Object。 更重要的是我們可以通過規則按照自己的想法控制存儲的數據類型。

5、說說List,Set,Map三者的區別

List(對付順序的好幫手): List接口存儲一組不唯一(可以有多個元素引用相同的對象),有序的對象
Set(注重獨一無二的性質):不允許重複的集合。不會有多個元素引用相同的對象。
Map(用Key來搜索的專): 使用鍵值對存儲。Map會維護與Key有關聯的值。兩個Key可以引用相同的對象,但Key不能重複,典型的Key是String類型,但也可以是任何對象。

6、Array與ArrayList有什麼不一樣?

Array與ArrayList都是用來存儲數據的集合。ArrayList底層是使用數組實現的,但是arrayList對數組進行了封裝和功能擴展,擁有許多原生數組沒有的一些功能。我們可以理解成ArrayList是Array的一個升級版。

7、Map有什麼特點

以鍵值對存儲數據
元素存儲循序是無序的
不允許出現重複鍵

8、集合類存放於 Java.util 包中, 主要有幾 種接口

主要包含set(集)、 list(列表包含 Queue)和 map(映射)。

  1. Collection: Collection 是集合 List、 Set、 Queue 的最基本的接口。
  2. Iterator:迭代器,可以通過迭代器遍歷集合中的數據
  3. Map:是映射表的基礎接口 在這裏插入圖片描述

9、什麼是list接口

Java 的 List 是非常常用的數據類型。 List 是有序的 Collection。 Java List 一共三個實現類:分別是 ArrayList、 Vector 和 LinkedList 。
list接口結構圖
在這裏插入圖片描述

10、說說ArrayList(數組)

ArrayList 是最常用的 List 實現類,內部是通過數組實現的,它允許對元素進行快速隨機訪問。數組的缺點是每個元素之間不能有間隔, 當數組大小不滿足時需要增加存儲能力,就要將已經有數組的數據複製到新的存儲空間中。 當從 ArrayList 的中間位置插入或者刪除元素時,需要對數組進行復制、移動、代價比較高。因此,它適合隨機查找和遍歷,不適合插入和刪除。

11、Vector( 數組實現、 線程同步)

Vector 與 ArrayList 一樣,也是通過數組實現的,不同的是它支持線程的同步,即某一時刻只有一個線程能夠寫 Vector,避免多線程同時寫而引起的不一致性,但實現同步需要很高的花費,因此,訪問它比訪問 ArrayList 慢 。

12、說說LinkList(鏈表)

LinkedList 是用鏈表結構存儲數據的,很適合數據的動態插入和刪除,隨機訪問和遍歷速度比較慢。另外,他還提供了 List 接口中沒有定義的方法,專門用於操作表頭和表尾元素,可以當作堆棧、隊列和雙向隊列使用

13、什麼Set集合

Set 注重獨一無二的性質,該體系集合用於存儲無序(存入和取出的順序不一定相同)元素, 值不能重複。對象的相等性本質是對象 hashCode 值(java 是依據對象的內存地址計算出的此序號) 判斷的, 如果想要讓兩個不同的對象視爲相等的,就必須覆蓋 Object 的 hashCode 方法和 equals 方法。
set結構結構圖在這裏插入圖片描述

14、HashSet( Hash 表)

哈希表邊存放的是哈希值。 HashSet 存儲元素的順序並不是按照存入時的順序(和 List 顯然不同) 而是按照哈希值來存的所以取數據也是按照哈希值取得。元素的哈希值是通過元素的hashcode 方法來獲取的, HashSet 首先判斷兩個元素的哈希值,如果哈希值一樣,接着會比較equals 方法 如果 equls 結果爲 true , HashSet 就視爲同一個元素。如果 equals 爲 false 就不是同一個元素。
哈希值相同 equals 爲 false 的元素是怎麼存儲呢,就是在同樣的哈希值下順延(可以認爲哈希值相同的元素放在一個哈希桶中)。也就是哈希一樣的存一列。 如圖 1 表示 hashCode 值不相同的情況; 圖 2 表示 hashCode 值相同,但 equals 不相同的情況。在這裏插入圖片描述
HashSet 通過 hashCode 值來確定元素在內存中的位置。 一個 hashCode 位置上可以存放多個元素。

15、什麼是TreeSet(二叉樹)

  1. TreeSet()是使用二叉樹的原理對新 add()的對象按照指定的順序排序(升序、降序),每增加一個對象都會進行排序,將對象插入的二叉樹指定的位置。
  2. Integer 和 String 對象都可以進行默認的 TreeSet 排序,而自定義類的對象是不可以的, 自己定義的類必須實現 Comparable 接口,並且覆寫相應的 compareTo()函數,纔可以正常使用。
  3. 在覆寫 compare()函數時,要返回相應的值才能使 TreeSet 按照一定的規則來排序
  4. 比較此對象與指定對象的順序。如果該對象小於、等於或大於指定對象,則分別返回負整數、零或正整數

16、說說LinkHashSet(HashSet+LinkedHashMap)

對於 LinkedHashSet 而言,它繼承與 HashSet、又基於LinkedHashMap 來實現的。LinkedHashSet 底層使用 LinkedHashMap 來保存所有元素,它繼承與 HashSet,其所有的方法操作上又與 HashSet 相同,因此 LinkedHashSet 的實現上非常簡單,只提供了四個構造方法,並通過傳遞一個標識參數,調用父類的構造器,底層構造一個 LinkedHashMap 來實現,在相關操作上與父類 HashSet 的操作相同,直接調用父類 HashSet 的方法即可。

17、HashMap(數組+鏈表+紅黑樹)

HashMap 根據鍵的 hashCode 值存儲數據,大多數情況下可以直接定位到它的值,因而具有很快的訪問速度,但遍歷順序卻是不確定的。 HashMap 最多隻允許一條記錄的鍵爲 null,允許多條記
錄的值爲 null。 HashMap 非線程安全,即任一時刻可以有多個線程同時寫 HashMap,可能會導致數據的不一致。如果需要滿足線程安全,可以用 Collections 的 synchronizedMap 方法使HashMap 具有線程安全的能力,或者使用 ConcurrentHashMap。 我們用下面這張圖來介紹
HashMap 的結構。在這裏插入圖片描述
大方向上, HashMap 裏面是一個數組,然後數組中每個元素是一個單向鏈表。上圖中,每個綠色的實體是嵌套類 Entry 的實例, Entry 包含四個屬性: key, value, hash 值和用於單向鏈表的 next。

  1. capacity:當前數組容量,始終保持 2^n,可以擴容,擴容後數組大小爲當前的 2 倍。
  2. oadFactor:負載因子,默認爲 0.75。
  3. threshold:擴容的閾值,等於 capacity * loadFactor
    Java8 對 HashMap 進行了一些修改, 最大的不同就是利用了紅黑樹,所以其由 數組+鏈表+紅黑樹 組成。
    根據 Java7 HashMap 的介紹,我們知道,查找的時候,根據 hash 值我們能夠快速定位到數組的具體下標,但是之後的話, 需要順着鏈表一個個比較下去才能找到我們需要的,時間複雜度取決於鏈表的長度,爲 O(n)。爲了降低這部分的開銷,在 Java8 中, 當鏈表中的元素超過了 8 個以後,會將鏈表轉換爲紅黑樹,在這些位置進行查找的時候可以降低時間複雜度爲 O(logN)。 在這裏插入圖片描述

18、說說ConcurrentHashMap

Segment 段
ConcurrentHashMap 和 HashMap 思路是差不多的,但是因爲它支持併發操作,所以要複雜一些。整個 ConcurrentHashMap 由一個個 Segment 組成, Segment 代表”部分“或”一段“的
意思,所以很多地方都會將其描述爲分段鎖。注意,行文中,我很多地方用了“槽”來代表一個segment。 線程安全(Segment 繼承 ReentrantLock 加鎖) 簡單理解就是, ConcurrentHashMap 是一個 Segment 數組, Segment 通過繼承ReentrantLock 來進行加鎖,所以每次需要加鎖的操作鎖住的是一個 segment,這樣只要保證每個 Segment 是線程安全的,也就實現了全局的線程安全
在這裏插入圖片描述
並行度(默認 16) concurrencyLevel:並行級別、併發數、 Segment 數,怎麼翻譯不重要,理解它。默認是 16,也就是說ConcurrentHashMap 有 16 個 Segments,所以理論上, 這個時候,最多可以同時支持 16 個線程併發寫,只要它們的操作分別分佈在不同的 Segment 上。這個值可以在初始化的時候設置爲其他值,但是一旦初始化以後,它是不可以擴容的。再具體到每個 Segment 內部,其實每個 Segment 很像之前介紹的 HashMap,不過它要保證線程安全,所以處理起來要麻煩些。
Java8 實現 (引入了紅黑樹)
Java8 對 ConcurrentHashMap 進行了比較大的改動,Java8 也引入了紅黑樹。 在這裏插入圖片描述

19、HashTable(線程安全)

Hashtable 是遺留類,很多映射的常用功能與 HashMap 類似,不同的是它承自 Dictionary 類,並且是線程安全的,任一時間只有一個線程能寫 Hashtable,併發性不如 ConcurrentHashMap,因爲 ConcurrentHashMap 引入了分段鎖。 Hashtable 不建議在新代碼中使用,不需要線程安全的場合可以用 HashMap 替換,需要線程安全的場合可以用 ConcurrentHashMap 替換

20、TreeMap(可排序)

TreeMap 實現 SortedMap 接口,能夠把它保存的記錄根據鍵排序,默認是按鍵值的升序排序,也可以指定排序的比較器,當用 Iterator 遍歷 TreeMap 時,得到的記錄是排過序的。如果使用排序的映射,建議使用 TreeMap。在使用 TreeMap 時, key 必須實現 Comparable 接口或者在構造 TreeMap 傳入自定義的Comparator,否則會在運行時拋出 java.lang.ClassCastException 類型的異常。
參考: https://www.ibm.com/developerworks/cn/java/j-lo-tree/index.html

21、LinkHashMap(記錄插入順序)

LinkedHashMap 是 HashMap 的一個子類,保存了記錄的插入順序,在用 Iterator 遍歷LinkedHashMap 時,先得到的記錄肯定是先插入的,也可以在構造時帶參數,按照訪問次序排序。
參考 1: http://www.importnew.com/28263.html
參考 2: http://www.importnew.com/20386.html#comment-648123

22、泛型類

泛型類的聲明和非泛型類的聲明類似,除了在類名後面添加了類型參數聲明部分。和泛型方法一樣,泛型類的類型參數聲明部分也包含一個
或多個類型參數,參數間用逗號隔開。一個泛型參數,也被稱爲一個類型變量,是用於指定一個泛型類型名稱的標識符。因爲他們接受一個
或多個參數,這些類被稱爲參數化的類或參數化的類型。
在這裏插入圖片描述

23、類型通配符? 類 型 通 配 符 一 般 是 使 用 ?

代 替 具 體 的 類 型 參 數 。 例 如 List<?> 在 邏 輯 上 是List,List 等所有 List<具體類型實參>的父類。

24、類型擦除

Java 中的泛型基本上都是在編譯器這個層次來實現的。在生成的 Java 字節代碼中是不包含泛型中的類型信息的。使用泛型的時候加上的類型參數,會被編譯器在編譯的時候去掉。這個過程就稱爲類型擦除。如在代碼中定義的 List和 List等類型,在編譯之後都會變成 List。 JVM 看到的只是 List,而由泛型附加的類型信息對 JVM 來說是不可見的。類型擦除的基本過程也比較簡單,首先是找到用來替換類型參數的具體類。這個具體類一般是 Object。如果指定了類型參數的上界的話,則使用這個上界。把代碼中的類型參數都替換成具體的類。

歡迎關注微信公衆號【慕容千語】

在這裏插入圖片描述

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