Java集合框架爲Java編程語言的基礎,也是Java面試中很重要的一個知識點。這裏,我列出了一些關於Java集合的重要問題和答案。java
每種編程語言中都有集合,最初的Java版本包含幾種集合類:Vector
、Stack
、HashTable
和Array
。git
隨着集合的普遍使用,Java1.2
提出了囊括全部集合接口、實現和算法的集合框架。在保證線程安全的狀況下使用泛型和併發集合類,Java已經經歷了好久。它還包括在Java併發包中,阻塞接口以及它們的實現。github
集合框架的部分優勢以下:面試
(1)使用核心集合類下降開發成本,而非實現咱們本身的集合類。算法
(2)隨着使用通過嚴格測試的集合框架類,代碼質量會獲得提升。編程
(3)經過使用JDK附帶的集合類,能夠下降代碼維護成本。設計模式
(4)複用性和可操做性。數組
1.Java1.5引入了泛型,全部的集合接口和實現都大量地使用它。安全
2.泛型容許咱們爲集合提供一個能夠容納的對象類型,所以,若是你添加其它類型的任何元素,它會在編譯時報錯。微信
3.這避免了在運行時出現ClassCastException,由於你將會在編譯時獲得報錯信息。
4.泛型也使得代碼整潔,咱們不須要使用顯式轉換和instanceOf操做符。
5.它也給運行時帶來好處,由於不會產生類型檢查的字節碼指令。
Collection
爲集合層級的根接口。一個集合表明一組對象,這些對象即爲它的元素。Java平臺不提供這個接口任何直接的實現。
Set
是一個不能包含重複元素的集合。這個接口對數學集合抽象進行建模,被用來表明集合,就如一副牌。
List
是一個有序集合,能夠包含重複元素。你能夠經過它的索引來訪問任何元素。List更像長度動態變換的數組。
Map
是一個將key映射到value的對象.一個Map不能包含重複的key:每一個key最多隻能映射一個value。
一些其它的接口有Queue、Dequeue、SortedSet、SortedMap和ListIterator。
儘管Map
接口和它的實現也是集合框架的一部分,但Map
不是集合,集合也不是Map
。所以,Map
繼承Collection
毫無心義,反之亦然。
若是Map
繼承Collection
接口,那麼元素去哪兒?Map包含key-value對,它提供抽取key或value列表集合的方法,可是它不適合「一組對象」規範。
ArrayList和Vector在不少時候都很相似。
(1)二者都是基於索引的,內部由一個數組支持。
(2)二者維護插入的順序,咱們能夠根據插入順序來獲取元素。
(3)ArrayList和Vector的迭代器實現都是fail-fast的。
(4)ArrayList和Vector二者容許null值,也可使用索引值對元素進行隨機訪問。
如下是ArrayList和Vector的不一樣點。
(1)Vector是同步的,而ArrayList不是。然而,若是你尋求在迭代的時候對列表進行改變,你應該使用CopyOnWriteArrayList。
(2)ArrayList比Vector快,它由於有同步,不會過載。
(3)ArrayList更加通用,由於咱們可使用Collections工具類輕易地獲取同步列表和只讀列表。
Array能夠容納基本類型和對象,而ArrayList只能容納對象。
Array是指定大小的,而ArrayList大小是固定的。
Array沒有提供ArrayList那麼多功能,好比addAll、removeAll和iterator等。儘管ArrayList明顯是更好的選擇,但也有些時候Array比較好用。
(1)若是列表的大小已經指定,大部分狀況下是存儲和遍歷它們。
(2)對於遍歷基本數據類型,儘管Collections使用自動裝箱來減輕編碼任務,在指定大小的基本類型的列表上工做也會變得很慢。
(3)若是你要使用多維數組,使用[][]比List>更容易。
ArrayList和LinkedList二者都實現了List接口,可是它們之間有些不一樣。
1)ArrayList是由Array所支持的基於一個索引的數據結構,因此它提供對元素的隨機訪問,複雜度爲O(1),但LinkedList存儲一系列的節點數據,每一個節點都與前一個和下一個節點相鏈接。因此,儘管有使用索引獲取元素的方法,內部實現是從起始點開始遍歷,遍歷到索引的節點而後返回元素,時間複雜度爲O(n),比ArrayList要慢。 2)與ArrayList相比,在LinkedList中插入、添加和刪除一個元素會更快,由於在一個元素被插入到中間的時候,不會涉及改變數組的大小,或更新索引。
3)LinkedList比ArrayList消耗更多的內存,由於LinkedList中的每一個節點存儲了先後節點的引用。
ArrayList、HashMap、TreeMap和HashTable類提供對元素的隨機訪問。
Vector、HashTable、Properties和Stack是同步類,因此它們是線程安全的,能夠在多線程環境下使用。Java1.5併發API包括一些集合類,容許迭代時修改,由於它們都工做在集合的克隆上,因此它們在多線程環境中是安全的。點擊這裏一文搞懂問什麼線程不安全。
Java1.5併發包(java.util.concurrent)包含線程安全集合類,容許在迭代時修改集合。迭代器被設計爲fail-fast的,會拋出ConcurrentModificationException。一部分類爲:CopyOnWriteArrayList、 ConcurrentHashMap、CopyOnWriteArraySet。
棧和隊列二者都被用來預存儲數據。java.util.Queue是一個接口,它的實現類在Java併發包中。隊列容許先進先出(FIFO)檢索元素,但並不是老是這樣。Deque接口容許從兩端檢索元素。棧與隊列很類似,但它容許對元素進行後進先出(LIFO)進行檢索。Stack是一個擴展自Vector的類,而Queue是一個接口。
Java.util.Collections是一個工具類僅包含靜態方法,它們操做或返回集合。它包含操做集合的多態算法,返回一個由指定集合支持的新集合和其它一些內容。這個類包含集合框架算法的方法,好比折半搜索、排序、混編和逆序等。
Comparable和Comparator接口被用來對對象集合或者數組進行排序。Comparable接口被用來提供對象的天然排序,咱們可使用它來提供基於單個邏輯的排序。Comparator接口被用來提供不一樣的排序算法,咱們能夠選擇須要使用的Comparator來對給定的對象集合進行排序。
Iterator接口提供遍歷任何Collection的接口。咱們能夠從一個Collection中使用迭代器方法來獲取迭代器實例。迭代器取代了Java集合框架中的Enumeration。迭代器容許調用者在迭代過程當中移除元素。
Enumeration的速度是Iterator的兩倍,也使用更少的內存。Enumeration是很是基礎的,也知足了基礎的須要。可是,與Enumeration相比,Iterator更加安全,由於當一個集合正在被遍歷的時候,它會阻止其它線程去修改集合。迭代器取代了Java集合框架中的Enumeration。迭代器容許調用者從集合中移除元素,而Enumeration不能作到。爲了使它的功能更加清晰,迭代器方法名已經通過改善。
(1)咱們可使用Iterator來遍歷Set和List集合,而ListIterator只能遍歷List。 (2)Iterator只能夠向前遍歷,而LIstIterator能夠雙向遍歷。 (3)ListIterator從Iterator接口繼承,而後添加了一些額外的功能,好比添加一個元素、替換一個元素、獲取前面或後面元素的索引位置。
每次咱們嘗試獲取下一個元素的時候,Iterator fail-fast屬性檢查當前集合結構裏的任何改動。若是發現任何改動,它拋出ConcurrentModificationException。Collection中全部Iterator的實現都是按fail-fast來設計的(ConcurrentHashMap和CopyOnWriteArrayList這類併發集合類除外)。
Iterator的fail-fast屬性與當前的集合共同起做用,所以它不會受到集合中任何改動的影響。Java.util包中的全部集合類都被設計爲fail-fast的,而java.util.concurrent中的集合類都爲fail-safe的。Fall—fast迭代器拋出ConcurrentModificationException,fall—safe迭代器從不拋出ConcurrentModificationException。
ConcurrentModificationException?在遍歷一個集合的時候咱們可使用併發集合類來避免ConcurrentModificationException,好比使用CopyOnWriteArrayList,而不是ArrayList。
(1)HashMap容許key和value爲null,而HashTable不容許。 (2)HashTable是同步的,而HashMap不是。因此HashMap適合單線程環境,HashTable適合多線程環境。 (3)在Java1.4中引入了LinkedHashMap,HashMap的一個子類,假如你想要遍歷順序,你很容易從HashMap轉向LinkedHashMap,可是HashTable不是這樣的,它的順序是不可預知的。 (4)HashMap提供對key的Set進行遍歷,所以它是fail-fast的,但HashTable提供對key的Enumeration進行遍歷,它不支持fail-fast。 (5)HashTable被認爲是個遺留的類,若是你尋求在迭代的時候修改Map,你應該使用CocurrentHashMap。
對於在Map中插入、刪除和定位元素這類操做,HashMap是最好的選擇。然而,假如你須要對一個有序的key集合進行遍歷,TreeMap是更好的選擇。基於你的collection的大小,也許向HashMap中添加元素會更快,將map換爲TreeMap進行有序key的遍歷。
若是咱們須要對一個對象數組進行排序,咱們可使用Arrays.sort()方法。若是咱們須要排序一個對象列表,咱們可使用Collection.sort()方法。兩個類都有用於天然排序(使用Comparable)或基於標準的排序(使用Comparator)的重載方法sort()。Collections內部使用數組排序方法,全部它們二者都有相同的性能,只是Collections須要花時間將列表轉換爲數組。
Array
,而不是 ArrayList
。ClassCastException
異常。Map
中使用 JDK
提供的不可變類做爲一個 key
,這樣能夠避免 hashcode
的實現和咱們自定義類的 equals
方法。null
,這樣能夠防止底層集合是空的。List
,Set
都是繼承自 Collection
接口。
注意:元素雖然無放入順序,可是元素在 Set 中的位置是有該元素的 hashcode 決定的,其位置實際上是固定的。
另外 List
支持 for
循環,也就是經過下標來遍歷,也能夠用迭代器,可是 Set
只能用迭代,由於他無序,沒法用下標來取得想要的值。
Set
和 List
對比:
HashSet
是用一個hash
表來實現的,所以,它的元素是無序的。添加,刪除和 HashSet
包括的方法的持續時間複雜度是O(1)
。 TreeSet
是用一個樹形結構實現的,所以,它是有序的。添加,刪除和 TreeSet
包含的方法的持續時間複雜度是 O(logn)
。
如何決定選用 HashMap
仍是 TreeMap
?
對於在Map
中插入、刪除和定位元素這類操做,HashMap
是最好的選擇。 然而,假如你須要對一個有序的 key 集合進行遍歷, TreeMap 是更好的選擇。 基於你的 collection
的大小,也許向 HashMap
中添加元素會更快,再將 HashMap
換爲 TreeMap
進行有序 key
的遍歷。
ConcurrentHashMap
是線程安全的 HashMap
的實現。主要區別以下:
一、ConcurrentHashMap 對整個桶數組進行了分割分段(Segment),而後在每個分段上都用 lock 鎖進行保護,相對 於Hashtable 的 syn 關鍵字鎖的粒度更精細了一些,併發性能更好。而 HashMap 沒有鎖機制,不是線程安全的。JDK8 以後,ConcurrentHashMap 啓用了一種全新的方式實現,利用 CAS 算法。 二、HashMap 的鍵值對容許有 null ,可是 ConCurrentHashMap 都不容許。
迭代器是一種設計模式,它是一個對象,它能夠遍歷並選擇序列中的對象,而開發人員不須要了解該序列的底層結構。迭代器一般被稱爲「輕量級」對象,由於建立它的代價小。Java中的Iterator功能比較簡單,而且只能單向移動:對已集合類中的任何一個實現類,均可以返回這樣一個Iterator對象。跟循環差很少。
好處是能夠適合用於任何一個類,並且java也對它進行了優化,比直接用index訪問快一點。迭代器是一種模式,它可使得對於序列類型的數據結構的遍歷行爲與被遍歷的對象分離,迭代器至關於有個指針,每次調用hasNext()方法若是返回值是true,說明有下一個元素,再執行next()方法得到該元素的值.
在迭代器Iteartor接口中,有如下3個方法: 1.hasNext() 該方法英語判斷集合對象是否還有下一個元素,若是已是最後一個元素則返回false 2.next() 把迭代器的指向移到下一個位置,同時,該方法返回下一個元素的引用 3.remove() 從迭代器指向的Collection中移除迭代器返回的最後一個元素,該操做使用的比較少。
PriorityQueue是一個基於優先級堆的無界有序隊列,它的元素是按照天然順序(natural order)排序的。在建立的時候,咱們能夠給它提供一個負責給元素排序的比較器。PriorityQueue不容許null值,由於他們沒有天然順序,或者說他們沒有任何的相關聯的比較器。最後,PriorityQueue不是線程安全的,入隊和出隊的時間複雜度是O(log(n))。
大O:描述了當數據結構裏面的元素增長的時候,算法的規模或者是性能在最壞的場景下有多麼好。 大O符號也可用來描述其餘的行爲,好比:內存消耗。由於集合類其實是數據結構,咱們通常使用大O符號基於時間,內存和性能來選擇最好的實現。大O符號能夠對大量數據的性能給出一個很好的說明。
有序數組最大的好處在於查找的時間複雜度是O(log n),而無序數組是O(n)。有序數組的缺點是插入操做的時間複雜度是O(n),由於值大的元素須要日後移動來給新元素騰位置。相反,無序數組的插入時間複雜度是常量O(1)。 因此,查找操做多的時候,使用有序;增刪操做多的使用無序的便可。
大廠筆試內容集合(內有詳細解析) 持續更新中....
歡迎關注我的微信公衆號:Coder編程 歡迎關注Coder編程公衆號,主要分享數據結構與算法、Java相關知識體系、框架知識及原理、Spring全家桶、微服務項目實戰、DevOps實踐之路、每日一篇互聯網大廠面試或筆試題以及PMP項目管理知識等。更多精彩內容正在路上~ 新建了一個qq羣:315211365,歡迎你們進羣交流一塊兒學習。謝謝了!也能夠介紹給身邊有須要的朋友。
文章收錄至 Github: github.com/CoderMerlin… Gitee: gitee.com/573059382/c… 歡迎關注並star~
![]()