Java面試題-集合(持續更新)

這裏寫圖片描述
  從上面的集合框架圖可以看到,Java 集合框架主要包括兩種類型的容器,一種是集合(Collection),存儲一個元素集合,另一種是圖(Map),存儲鍵/值對映射。Collection 接口又有 3 種子類型,List、Set 和 Queue,再下面是一些抽象類,最後是具體實現類,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等等。

接口描述

Collection 接口

Collection 是最基本的集合接口,一個 Collection 代表一組 Object,即 Collection 的元素, Java不提供直接繼承自Collection的類,只提供繼承於的子接口(如List和set)。Collection 接口存儲一組不唯一,無序的對象。

List 接口

List接口是一個有序的 Collection,使用此接口能夠精確的控制每個元素插入的位置,能夠通過索引(元素在List中位置,類似於數組的下標)來訪問List中的元素,第一個元素的索引爲 0,而且允許有相同的元素。
List 接口存儲一組不唯一,有序(插入順序)的對象。

Set

Set 具有與 Collection 完全一樣的接口,只是行爲上不同,Set 不保存重複的元素。Set 接口存儲一組唯一,無序的對象。

SortedSet

繼承於Set保存有序的集合。

Map

Map 接口存儲一組鍵值對象,提供key(鍵)到value(值)的映射。

Map.Entry

描述在一個Map中的一個元素(鍵/值對)。是一個Map的內部類。

SortedMap

繼承於 Map,使 Key 保持在升序排列。

Enumeration

這是一個傳統的接口和定義的方法,通過它可以枚舉(一次獲得一個)對象集合中的元素。這個傳統接口已被迭代器取代。

集合實現類(集合類)

AbstractCollection

實現了大部分的集合接口。

AbstractList

繼承於AbstractCollection 並且實現了大部分List接口。

AbstractSequentialList

繼承於 AbstractList ,提供了對數據元素的鏈式訪問而不是隨機訪問。

LinkedList

該類實現了List接口,允許有null(空)元素。主要用於創建鏈表數據結構,該類沒有同步方法,如果多個線程同時訪問一個List,則必須自己實現訪問同步,解決方法就是在創建List時候構造一個同步的List。例如:
Listlist=Collections.synchronizedList(newLinkedList(…));
LinkedList 查找效率低。

ArrayList

該類也是實現了List的接口,實現了可變大小的數組,隨機訪問和遍歷元素時,提供更好的性能。該類也是非同步的,在多線程的情況下不要使用。ArrayList 增長當前長度的50%,插入刪除效率低。

AbstractSet

繼承於AbstractCollection 並且實現了大部分Set接口。

HashSet

該類實現了Set接口,不允許出現重複元素,不保證集合中元素的順序,允許包含值爲null的元素,但最多隻能一個。

LinkedHashSet

具有可預知迭代順序的 Set 接口的哈希表和鏈接列表實現。

TreeSet

該類實現了Set接口,可以實現排序等功能。

AbstractMap

實現了大部分的Map接口。

HashMap

       HashMap 是一個散列表,它存儲的內容是鍵值對(key-value)映射。該類實現了Map接口,根據鍵的HashCode值存儲數據,具有很快的訪問速度,最多允許一條記錄的鍵爲null,不支持線程同步。

HashMap原理

       簡單來說,HashMap由數組+鏈表組成的,數組是HashMap的主體,鏈表則是主要爲了解決哈希衝突而存在的,如果定位到的數組位置不含鏈表(當前entry的next指向null),那麼對於查找,添加等操作很快,僅需一次尋址即可;如果定位到的數組包含鏈表,對於添加操作,其時間複雜度爲O(n),首先遍歷鏈表,存在即覆蓋,否則新增;對於查找操作來講,仍需遍歷鏈表,然後通過key對象的equals方法逐一比對查找。所以,性能考慮,HashMap中的鏈表出現越少,性能纔會越好。

HashMap爲什麼線程不安全

兩個線程同時執行了put()操作,並進入了transfer()環節。線程1完成所有節點移動後,線程2會把新表當成原表,會出現環型鏈表(e.next=e2 e2.next=e1 死循環)。ConcurrentHashMap如果 map 正在擴容,其他線程會事先判斷是否在擴肉甚至於還會幫助擴容,也就是多線程擴容

處理哈希衝突用的哪種方法

哈希衝突的解決方案有多種:開放定址法(發生衝突,繼續尋找下一塊未被佔用的存儲地址),再散列函數法,鏈地址法,而HashMap即是採用了鏈地址法,也就是數組+鏈表的方式。

ConcurrentHashMap 在Java7和Java8中的區別

Java7:採用了分段鎖的設計,只有在同一個分段內才存在競態關係,不同的分段鎖之間沒有鎖競爭
Java8:CAS(Compare-and-Swap),即比較並替換,樂觀鎖

TreeMap

繼承了AbstractMap,並且使用一顆樹。

WeakHashMap

繼承AbstractMap類,使用弱密鑰的哈希表。

LinkedHashMap

繼承於HashMap,使用元素的自然順序對元素進行排序.

IdentityHashMap

繼承AbstractMap類,比較文檔時使用引用相等。

Vector

該類和ArrayList非常相似,但是該類是同步的,可以用在多線程的情況,該類允許設置默認的增長長度,默認擴容方式爲原來的2倍。

stack

棧是Vector的一個子類,它實現了一個標準的後進先出的棧。

Dictionary

Dictionary 類是一個抽象類,用來存儲鍵/值對,作用和Map類相似。

Hashtable

Hashtable 是 Dictionary(字典) 類的子類,位於 java.util 包中。

Properties

Properties 繼承於 Hashtable,表示一個持久的屬性集,屬性列表中每個鍵及其對應值都是一個字符串。

BitSet

一個Bitset類創建一種特殊類型的數組來保存位值。BitSet中數組大小會隨需要增加。
以上內容整理來自:http://www.runoob.com/java/java-collections.html

Queue

阻塞隊列與普通隊列的區別在於,當隊列是空的時,從隊列中獲取元素的操作將會被阻塞,或者當隊列是滿時,往隊列裏添加元素的操作會被阻塞。試圖從空的阻塞隊列中獲取元素的線程將會被阻塞,直到其他的線程往空的隊列插入新的元素。同樣,試圖往已滿的阻塞隊列中添加新元素的線程同樣也會被阻塞,直到其他的線程使隊列重新變得空閒起來,如從隊列中移除一個或者多個元素,或者完全清空隊列.
有界隊列:就是有固定大小的隊列。比如設定了固定大小的 LinkedBlockingQueue,又或者大小爲 0,只是在生產者和消費者中做中轉用的 SynchronousQueue。
無界隊列:指的是沒有設置固定大小的隊列。這些隊列的特點是可以直接入列,直到溢出。當然現實幾乎不會有到這麼大的容量(超過 Integer.MAX_VALUE),所以從使用者的體驗上,就相當於 “無界”。比如沒有設定固定大小的 LinkedBlockingQueue。

ConcurrentLinkedQueue

高性能無阻塞無界隊列

ArrayBlockingQueue

基於數組的阻塞隊列,有界隊列

LinkedBlockingQueue

阻塞隊列,無界隊列

Comparable和Comparator區別比較

       Comparable是排序接口,若一個類實現了Comparable接口,就意味着“該類支持排序”。而Comparator是比較器,我們若需要控制某個類的次序,可以建立一個“該類的比較器”來進行排序。
       Comparable相當於“內部比較器”,而Comparator相當於“外部比較器”。
  兩種方法各有優劣, 用Comparable 簡單, 只要實現Comparable 接口的對象直接就成爲一個可以比較的對象,但是需要修改源代碼。 用Comparator 的好處是不需要修改源代碼, 而是另外實現一個比較器, 當某個自定義的對象需要作比較的時候,把比較器和對象一起傳遞過去就可以比大小了, 並且在Comparator 裏面用戶可以自己實現複雜的可以通用的邏輯,使其可以匹配一些比較簡單的對象,那樣就可以節省很多重複勞動了。

更多內容請訪問:http://lyhkmm.com

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