Java面試題:Java中的集合及其繼承關係

關於集合的體系是每一個人都應該爛熟於心的,尤爲是對咱們常用的List,Map的原理更該如此.這裏咱們看這張圖便可:java


v2-396d77120dd8c60afb6e67fa79972b73_hd.jpg


一、List、Set、Map是否繼承自Collection接口?

List、Set 是,Map 不是。Map是鍵值對映射容器,與List和Set有明顯的區別,而Set存儲的零散的元素且不容許有重複元素(數學中的集合也是如此),List是線性結構的容器,適用於按數值索引訪問元素的情形。面試

二、闡述ArrayList、Vector、LinkedList的存儲性能和特性。

ArrayList 和Vector都是使用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增長和插入元素,它們都容許直接按序號索引元素,可是插入元素要涉及數組元素移動等內存操做,因此索引數據快而插入數據慢。Vector中的方法因爲添加了synchronized修飾,所以Vector是線程安全的容器,但性能上較ArrayList差,所以已是Java中的遺留容器。算法

LinkedList使用雙向鏈表實現存儲(將內存中零散的內存單元經過附加的引用關聯起來,造成一個能夠按序號索引的線性結構,這種鏈式存儲方式與數組的連續存儲方式相比,內存的利用率更高),按序號索引數據須要進行前向或後向遍歷,可是插入數據時只須要記錄本項的先後項便可,因此插入速度較快。編程

Vector屬於遺留容器(Java早期的版本中提供的容器,除此以外,Hashtable、Dictionary、BitSet、Stack、Properties都是遺留容器),已經不推薦使用,可是因爲ArrayList和LinkedListed都是非線程安全的,若是遇到多個線程操做同一個容器的場景,則能夠經過工具類Collections中的synchronizedList方法將其轉換成線程安全的容器後再使用(這是對裝潢模式的應用,將已有對象傳入另外一個類的構造器中建立新的對象來加強實現)。數組

三、Collection和Collections的區別?

Collection是一個接口,它是Set、List等容器的父接口;Collections是個一個工具類,提供了一系列的靜態方法來輔助容器操做,這些方法包括對容器的搜索、排序、線程安全化等等。安全

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

List以特定索引來存取元素,能夠有重複元素。數據結構

Set不能存放重複元素(用對象的equals()方法來區分元素是否重複)。多線程

Map保存鍵值對(key-value pair)映射,映射關係能夠是一對一或多對一。併發

Set和Map容器都有基於哈希存儲和排序樹的兩種實現版本,基於哈希存儲的版本理論存取時間複雜度爲O(1),而基於排序樹版本的實如今插入或刪除元素時會按照元素或元素的鍵(key)構成排序樹從而達到排序和去重的效果。app

五、List和Set區別

Set是最簡單的一種集合。集合中的對象不按特定的方式排序,而且沒有重複對象。

  • HashSet: HashSet類按照哈希算法來存取集合中的對象,存取速度比較快

  • TreeSet :TreeSet類實現了SortedSet接口,可以對集合中的對象進行排序。

List的特徵是其元素以線性方式存儲,集合中能夠存放重複對象。

  • ArrayList() : 表明長度能夠改變得數組。能夠對元素進行隨機的訪問,向ArrayList()中插入與刪除元素的速度慢。

  • LinkedList(): 在實現中採用鏈表數據結構。插入和刪除速度快,訪問速度慢。

六、LinkedHashMap和PriorityQueue的區別

PriorityQueue 是一個優先級隊列,保證最高或者最低優先級的的元素老是在隊列頭部,可是 LinkedHashMap 維持的順序是元素插入的順序。當遍歷一個 PriorityQueue 時,沒有任何順序保證,可是 LinkedHashMap 課保證遍歷順序是元素插入的順序。

七、WeakHashMap與HashMap的區別是什麼?

WeakHashMap 的工做與正常的 HashMap 相似,可是使用弱引用做爲 key,意思就是當 key 對象沒有任何引用時,key/value 將會被回收。

八、ArrayList和LinkedList的區別?

最明顯的區別是 ArrrayList底層的數據結構是數組,支持隨機訪問,而 LinkedList 的底層數據結構是雙向循環鏈表,不支持隨機訪問。使用下標訪問一個元素,ArrayList 的時間複雜度是 O(1),而 LinkedList 是 O(n)。

相對於ArrayList,LinkedList的插入,添加,刪除操做速度更快,由於當元素被添加到集合任意位置的時候,不須要像數組那樣從新計算大小或者是更新索引。

LinkedList比ArrayList更佔內存,由於LinkedList爲每個節點存儲了兩個引用,一個指向前一個元素,一個指向下一個元素。

九、ArrayList和Array有什麼區別?

Array能夠容納基本類型和對象,而ArrayList只能容納對象。

Array是指定大小的,而ArrayList大小是固定的

十、ArrayList與Vector區別

ArrayList和Vector在不少時候都很相似。

  • 二者都是基於索引的,內部由一個數組支持。

  • 二者維護插入的順序,咱們能夠根據插入順序來獲取元素。

  • ArrayList和Vector的迭代器實現都是fail-fast的。

  • ArrayList和Vector二者容許null值,也可使用索引值對元素進行隨機訪問。

如下是ArrayList和Vector的不一樣點。

  • Vector是同步的,而ArrayList不是。然而,若是你尋求在迭代的時候對列表進行改變,你應該使用CopyOnWriteArrayList。

  • ArrayList比Vector快,它由於有同步,不會過載。

  • ArrayList更加通用,由於咱們可使用Collections工具類輕易地獲取同步列表和只讀列表。

十一、HashMap和Hashtable的區別

HashMap和Hashtable都實現了Map接口,所以不少特性很是類似。可是,他們有如下不一樣點:

  • HashMap容許鍵和值是null,而Hashtable不容許鍵或者值是null。

  • Hashtable是同步的,而HashMap不是。所以,HashMap更適合於單線程環境,而Hashtable適合於多線程環境。

  • HashMap提供了可供應用迭代的鍵的集合,所以,HashMap是快速失敗的。另外一方面,Hashtable提供了對鍵的列舉(Enumeration)。

  • 通常認爲Hashtable是一個遺留的類。

十二、HashSet和HashMap區別

  • HashSet實現了Set接口,它不容許集合中有重複的值。它存儲的是對象

  • HashMap實現了Map接口,Map接口對鍵值對進行映射。Map中不容許重複的鍵。Map接口有兩個基本的實現,HashMap和TreeMap。

1三、HashMap和ConcurrentHashMap的區別

  • ConcurrentHashMap對整個桶數組進行了分段,而HashMap則沒有。

  • ConcurrentHashMap在每個分段上都用鎖進行保護,從而讓鎖的粒度更精細一些,併發性能更好,而HashMap沒有鎖機制,不是線程安全的。

引入ConcurrentHashMap是爲了在同步集合HashTable之間有更好的選擇,HashTable與HashMap、ConcurrentHashMap主要的區別在於HashMap不是同步的、線程不安全的和不適合應用於多線程併發環境下,而ConcurrentHashMap是線程安全的集合容器,特別是在多線程和併發環境中,一般做爲Map的主要實現。

1四、Comparator和Comparable的區別?

Comparable 接口用於定義對象的天然順序,而 comparator 一般用於定義用戶定製的順序。Comparable 老是隻有一個,可是能夠有多個 comparator 來定義對象的順序。

1五、poll()方法和remove()方法區別?

poll() 和 remove() 都是從隊列中取出一個元素,可是 poll() 在獲取元素失敗的時候會返回空,可是 remove() 失敗的時候會拋出異常。

1六、ArrayList、HashMa和LinkedList的默認空間是多少?擴容機制是什麼

  • ArrayList 的默認大小是 10 個元素。擴容點規則是,新增的時候發現容量不夠用了,就去擴容;擴容大小規則是:擴容後的大小= 原始大小+原始大小/2 + 1。

  • HashMap 的默認大小是16個元素(必須是2的冪)。擴容因子默認0.75,擴容機制.(當前大小 和 當前容量 的比例超過了 擴容因子,就會擴容,擴容後大小爲 一倍。例如:初始大小爲 16 ,擴容因子 0.75 ,當容量爲12的時候,比例已是0.75 。觸發擴容,擴容後的大小爲 32.)

  • LinkedList 是一個雙向鏈表,沒有初始化大小,也沒有擴容的機制,就是一直在前面或者後面新增就好。

private static final int DEFAULT_CAPACITY = 10;

//from HashMap.java JDK 7
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

1七、如何實現集合排序?

你可使用有序集合,如 TreeSet 或 TreeMap,你也可使用有順序的的集合,如 list,而後經過 Collections.sort() 來排序。

1八、如何打印數組內容

你可使用 Arrays.toString() 和 Arrays.deepToString() 方法來打印數組。因爲數組沒有實現 toString() 方法,因此若是將數組傳遞給 System.out.println() 方法,將沒法打印出數組的內容,可是 Arrays.toString() 能夠打印每一個元素。

1九、LinkedList的是單向鏈表仍是雙向?

雙向循環列表,具體實現自行查閱源碼.

20、TreeMap是實現原理

採用紅黑樹實現,具體實現自行查閱源碼.

2一、遍歷ArrayList時如何正確移除一個元素

該問題的關鍵在於面試者使用的是 ArrayList 的 remove() 仍是 Iterator 的 remove()方法。這有一段示例代碼,是使用正確的方式來實如今遍歷的過程當中移除元素,而不會出現 ConcurrentModificationException 異常的示例代碼。

2二、什麼是ArrayMap?它和HashMap有什麼區別?

ArrayMap是Android SDK中提供的,非Android開發者能夠略過。

ArrayMap是用兩個數組來模擬map,更少的內存佔用空間,更高的效率。

具體參考這篇文章:ArrayMap VS HashMap:http://lvable.com/?p=217%5D

2三、如何決定選用HashMap仍是TreeMap?

對於在Map中插入、刪除和定位元素這類操做,HashMap是最好的選擇。然而,假如你須要對一個有序的key集合進行遍歷,TreeMap是更好的選擇。基於你的collection的大小,也許向HashMap中添加元素會更快,將map換爲TreeMap進行有序key的遍歷。

2四、HashMap的實現原理

  1. HashMap概述: HashMap是基於哈希表的Map接口的非同步實現。此實現提供全部可選的映射操做,並容許使用null值和null鍵。此類不保證映射的順序,特別是它不保證該順序恆久不變。

  2. HashMap的數據結構: 在java編程語言中,最基本的結構就是兩種,一個是數組,另一個是模擬指針(引用),全部的數據結構均可以用這兩個基本結構來構造的,HashMap也不例外。HashMap其實是一個「鏈表散列」的數據結構,即數組和鏈表的結合體。

當咱們往Hashmap中put元素時,首先根據key的hashcode從新計算hash值,根絕hash值獲得這個元素在數組中的位置(下標),若是該數組在該位置上已經存放了其餘元素,那麼在這個位置上的元素將以鏈表的形式存放,新加入的放在鏈頭,最早加入的放入鏈尾.若是數組中該位置沒有元素,就直接將該元素放到數組的該位置上.

須要注意Jdk 1.8中對HashMap的實現作了優化,當鏈表中的節點數據超過八個以後,該鏈表會轉爲紅黑樹來提升查詢效率,從原來的O(n)到O(logn)

2五、ConcurrentHashMap 的工做原理及代碼實現

ConcurrentHashMap具體是怎麼實現線程安全的呢,確定不多是每一個方法加synchronized,那樣就變成了HashTable。

從ConcurrentHashMap代碼中能夠看出,它引入了一個「分段鎖」的概念,具體能夠理解爲把一個大的Map拆分紅N個小的HashTable,根據key.hashCode()來決定把key放到哪一個HashTable中。

在ConcurrentHashMap中,就是把Map分紅了N個Segment,put和get的時候,都是現根據key.hashCode()算出放到哪一個Segment中。

2六、Fail-fast和Fail-safe有什麼區別

Iterator的fail-fast屬性與當前的集合共同起做用,所以它不會受到集合中任何改動的影響。Java.util包中的全部集合類都被設計爲fail->fast的,而java.util.concurrent中的集合類都爲fail-safe的。當檢測到正在遍歷的集合的結構被改變時,Fail-fast迭代器拋出ConcurrentModificationException,而fail-safe迭代器從不拋出ConcurrentModificationException。

2七、說出幾點 Java 中使用 Collections 的最佳實踐

這是我在使用 Java 中 Collectionc 類的一些最佳實踐:

  • 使用正確的集合類,例如,若是不須要同步列表,使用 ArrayList 而不是 Vector。

  • 優先使用併發集合,而不是對集合進行同步。併發集合提供更好的可擴展性。

  • 使用接口表明和訪問集合,如使用List存儲 ArrayList,使用 Map 存儲 HashMap 等等。

  • 使用迭代器來循環集合。

  • 使用集合的時候使用泛型。

2八、BlockingQueue是什麼?

Java.util.concurrent.BlockingQueue是一個隊列,在進行檢索或移除一個元素的時候,它會等待隊列變爲非空;當在添加一個元素時,它會等待隊列中的可用空間。BlockingQueue接口是Java集合框架的一部分,主要用於實現生產者-消費者模式。咱們不須要擔憂等待生產者有可用的空間,或消費者有可用的對象,由於它都在BlockingQueue的實現類中被處理了。Java提供了集中BlockingQueue的實現,好比ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue,、SynchronousQueue

2九、隊列和棧是什麼,列出它們的區別?

棧和隊列二者都被用來預存儲數據。java.util.Queue是一個接口,它的實現類在Java併發包中。隊列容許先進先出(FIFO)檢索元素,但並不是老是這樣。Deque接口容許從兩端檢索元素。

棧與隊列很類似,但它容許對元素進行後進先出(LIFO)進行檢索。

Stack是一個擴展自Vector的類,而Queue是一個接口。

相關文章
相關標籤/搜索