本文關鍵詞:html
java集合框架 框架設計理念 容器 繼承層級結構 繼承圖 集合框架中的抽象類 主要的實現類 實現類特性 集合框架分類 集合框架併發包 併發實現類java
由一個或多個肯定的元素所構成的總體叫作集合。程序員
容器用來包裝或裝載物品的貯存器 (如箱、罐、壇)或者成形或柔軟不成形的包覆材料。算法
在Java中的Collection框架,有的人叫作集合有的叫作容器,無論怎麼叫基本上也離不開"把元素裝起來"這個本質.編程
咱們的世界裏面豐富多彩,有各類各樣的事物,不少事物都會有他的容器api
人的生活天然也離不開各類容器,喝水須要杯子,吃飯須要碗,煮湯須要鍋,這都是容器;數組
容器有各類各樣的形狀,也有各類各樣的特性;安全
好比茶杯有的有蓋子,有的沒有蓋子,水壺能夠從壺嘴往外倒水等數據結構
java是面向對象的語言,萬事萬物皆是對象,縱然有着千姿百態的各類不一樣類型多線程
因此想要在java對象中更加暢快的使用對象,天然也是須要容器的;
按照容器的概念,數組也是一種容器,能夠用於存放一個或者多個元素;
但是,數組只能保存同一種類型的元素,並且長度是固定的;
人們天然但願能夠有一種容器可以保存各類不一樣的類型的元素,而且長度是不固定的;
這也是集合框架設計的初衷;
提供一種能夠保存多種類型元素,而且長度不受限制的容器,來更加方便的保存對象;
因此java中的容器也就是java世界裏面承裝對象的器皿.
容器根本屬性在於存/取,以及一些其餘的附加的操做.
容器內部有其擺放形式:排成一行仍是扔到一堆?
也有他的存取順序:先進先出仍是先進後出的被壓倒最下面?
這是抽象的描述
對應到計算機科學的世界裏面,那便是數據結構與算法的描述
數據結構是指相互之間存在着一種或多種關係的數據元素的集合和該集合中數據元素之間的關係組成
數據結構中有線性結構,樹形結構等,形式有隊列 棧 鍵值對 等
至此,能夠這麼理解編程語言中的集合框架:
集合框架目的就只是爲了盛裝對象,操做對象
本質就是Java語言,針對於容器這一律念,數據結構與算法的描述實現.
更直白的說,也就只是數據結構與算法,java只是一個表現形式
好比LinkedList 他就是java語言對於雙向鏈表的一種描述,若是你懂雙向鏈表的原理,而且懂得java的語法,你也能夠實現一個LinkedList
不過,選取哪些數據結構,使用哪些算法,繼承層級如何安排,這是java本身的特色;
固然,並非說你用Java編寫一個雙向鏈表就是寫出來集合框架了Java是面向對象的語言,面向對象的三大基礎特徵,封裝繼承多態嘛想要給一門編程語言提供一個集合框架,天然不是寫幾個算法數據結構這麼簡單的事情Java中的集合框架是自頂而下設計的如同全部的對象的祖宗都是Object同樣集合框架天然也是有祖宗的,那就是Collection 這就表示集合 ,在Java中用來存儲元素的容器
不過也還有另一派,叫作Map ,如官方文檔中描述的那樣,Map並不算是集合,只不過是一種操做數據的結構而已可是Map也提供了相似集合似的存取元素,元素操做等功能廣義上按照咱們以前說的集合/容器的概念去理解的話,天然他也能夠算得上是Java集合的一份子因此通常都是把Map和Collection統稱爲Java的集合體系的鑑於Java語言的特性,集合體系中這些用於刻畫家族臉譜的東西,天然都是接口,除非特別指明,所提到的類型均爲接口
Collection中是一組獨立的元素而Map中則是一組成對的鍵值對元素
一組獨立的元素,Collection,中又能夠按照有序的列表和無序的集,這就是List 和Set固然還有Queue,隊列其實話說回來,爲什麼Queue直接繼承自Collection?有序和無序的並集不就已是總體了麼隊列不也算是一種特殊的List麼,的確隊列是一種特殊的List,並且,經常使用的實現類LinkedList
.....implements List<E>, Deque<E>..... 而且其中 interface Deque<E> extends Queue<E>
因此說,隊列邏輯思惟意義上就是列表中比較特殊的一種,只不過他的特殊性比較多
因此在實現代碼的時候把它單獨拿出來直接繼承自Collection 做爲一種大的分類
也我以爲也並無什麼太大的違和感,我的理解,歡迎指正
如今咱們已經"高屋建瓴"的把集合Collection分爲了 List Set Queue這三種,再加上剛纔說到的Map
四大天王已經誕生了
Set和Map自己是無序的,在此基礎上又增長了排序的概念
因此家族裏面又多出來sortedSet 和 sortedMap
既然有了排序的概念,那麼在此之上繼續增長個可搜索的功能也沒什麼好奇怪的
也就是
NavigableSet 和 NavigableMap
不得不說,美國人英語真好
Queue隊列中又分爲:
雙端隊列Deque (double ended queue)
因此主要的接口是這些:
Collection
|---List
|---Set
|---sortedSet
|---NavigableSet
|---Queue
|---Deque
|---Map
|---sortedMap
|---NavigableMap
至此,對於java集合來講,意識形態層面的設計已經完成.
一人心難如萬人意,集合框架設計者也明白這個道理
天然知道提供的實現類並不能知足全部人需求,天然有人想要本身實現,
若是從頭寫來一個天然是代價巨大,考慮到這點,集合框架提供了很多的抽象類,抽象類實現了大部分通用的方法
你想要實現,只須要繼承抽象類,而且實現必要的幾個方法便可
固然,集合的設計自己也是這個思路,一箭雙鵰,本身寫的這麼方便的東西,沒道理不用;
抽象類大多數以Abs開頭的
AbstractCollection:
提供了Collection的主要實現
Collection 下的大多數子類都繼承 AbstractCollection ,好比 List 的實現類, Set的實現類。
AbstractList
List接口的骨架實現,最大限度地減小實現由「隨機訪問」數據存儲(如數組)所支持的接口所需的工做量。
對於順序訪問數據(如連接列表),應該優先使用AbstractSequentialList。
AbstractSequentialList
List接口的骨架實現,以最大限度地減小實現由「順序訪問」數據存儲(如連接列表)支持的接口所需的工做量。
對於隨機訪問數據(如數組),應優先使用AbstractList。
AbstractSet
提供了Set接口的骨架實現,不會覆蓋AbstractCollection類中的任何實現。它只是增長了equals和hashCode的實現。
經過擴展此類來實現集合的過程與經過擴展AbstractCollection來實現集合的過程相同
不一樣之處在於此類的全部子類中的全部方法和構造函數都必須遵照Set接口施加的額外約束(例如,添加方法不得容許將一個對象的多個實例添加到一個集合中)。
AbstractQueue
提供了一些Queue操做的骨架實現
當基類實現不容許空元素時,此類中的實現適用。
方法add,remove和element分別基於offer,poll和peek,可是會拋出異常而不是經過false或null返回來指示失敗。
擴展此類的任何Queue實現類至少也須要定義方法Queue.offer(E),該方法不容許插入空元素
以及方法Queue.peek(),Queue.poll(),Collection.size()和Collection.iterator()。
一般,其餘方法也將被覆蓋。若是這些要求不能知足,請考慮派生AbstractCollection的子類。
AbstractMap
Map接口的骨架實現
要實現一個不可修改的映射,程序員只須要擴展這個類併爲entrySet方法提供一個實現,該方法返回Map映射的set-view。
一般,返回的集合是AbstractSet的一個實現。並且通常是內部類的形式
這個集合不該該支持add或remove方法,它的迭代器不該該支持remove方法。
EnumSet
用於枚舉類型的專用Set實現
主要的實現類有:
Collection下面:
其中List的實現類主要是:
(1)ArrayList
List接口的可調整大小數組實現。
實現List接口中全部的可選操做,並容許任意元素,包括null。
除了實現List接口以外,該類還提供了一些方法來控制用於內部存儲列表的數組大小。(這個類大體至關於Vector,除了它是不一樣步的。)
此實現是不一樣步。
(2)LinkedList
List和Deque接口的雙端鏈表實現。實現List接口全部的可選操做,並容許任意元素(包括null)。
此實現是不一樣步。
(3)Vector
Vector類實現了一個可增加的對象數組。
像數組同樣,它包含可使用整數索引訪問的組件。
不一樣於數組的是,Vector的大小可根據須要增大或減少,以適應在建立Vector以後添加和移除項目。
同步的
(4)Stack
Stack類表示後進先出(LIFO)對象堆棧。
它使用五個操做來擴展類Vector,這樣子能夠將一個Vector視爲一個堆棧。
提供了:
一般的推送和彈出操做,
以及一種方法來查看堆棧中的頂層項目,
一種方法來測試堆棧是否爲空,
以及一種方法來搜索堆棧中的項目並發現它有多遠是從頂部。
當第一次建立堆棧時,它不包含任何元素。
Deque接口及其實現提供了更完整和一致的LIFO堆棧操做集,應優先使用此類。例如:
Deque<Integer> stack = new ArrayDeque<Integer>();
Set下面主要是:
(1)HashSet
這個類實現了Set接口
由一個哈希表(其實是一個HashMap實例)支持。
它對集合的迭代次序沒有任何保證;
特別是,它不能保證順序會隨着時間的推移保持不變。這個類容許null元素。
HashSet應該是你在沒有特殊要求下的默認選擇
這個類爲基本操做(添加,刪除,包含和大小)提供了恆定的時間性能,假設散列函數在桶之間正確地分散元素。
迭代此集合須要的時間與HashSet實例的大小(元素數量)加上支持HashMap實例的「容量」(桶的數量)的總和成正比。
所以,若是迭代性能很重要,不要將初始容量設置得過高(或者負載因子過低)是很是重要的。
非同步的
(2)TreeSet
基於TreeMap的NavigableSet實現。
這些元素使用它們的天然順序或者在建立集合時提供的比較器進行排序,具體取決於使用哪一個構造函數。
這個實現保證:基本操做(添加,移除和包含)的時間複雜度爲 log(n)非同步的
(3)LinkedHashSet
Set接口的哈希表和鏈表實現,具備可預測的迭代順序。
這個實現與HashSet的不一樣之處在於它保持了一個雙向鏈表,它貫穿其全部條目。
此連接列表定義迭代排序,即元素插入到集合中的順序(插入順序)。
請注意,若是元素從新插入到集合中,則插入順序不受影響。
(若是s.contains(e)在調用以前當即返回true,則調用s.add(e)時,將元素e從新插入到集合s中。)
非同步的
HashSet的性能老是比TreeSet好,特別是添加和查詢元素
TreeSet存在的惟一緣由就是能夠維持元素的排序狀態,因此,只有當須要一個排好序的Set時
才應該使用TreeSet
對於插入操做 LinkedHashSet比HashSet的代價要高
Queue的:
(1)ArrayDeque
Deque接口的可調整大小的實現。
Array deques沒有容量限制;根據使用狀況動態增加.
它們不是線程安全的
在沒有外部同步的狀況下,它們不支持多線程的併發訪問。
禁止使用空元素
當用做堆棧時,該類可能比Stack快,而且在用做隊列時比LinkedList快。
這個類的迭代器方法返回的迭代器是快速失敗機制的,會拋異常
ConcurrentModificationException
.
(2)PriorityQueue
基於優先級堆的無限優先級隊列
優先級隊列的元素根據其天然排序或隊列構建時提供的比較器進行排序,具體取決於使用哪一個構造函數
優先級隊列不容許空元素。依賴於天然順序的優先級隊列也不容許插入非可比對象(這樣作可能致使ClassCastException)。
非同步的
優先級隊列是無界的,但具備控制用於存儲隊列中元素的數組大小的內部容量。
它老是至少與隊列大小同樣大。隨着元素被添加到優先級隊列中,其容量會自動增長。
Map下面:
(1)HashMap
基於哈希表的Map接口實現
該實現提供了全部可選的Map操做,並容許使用空值和空鍵
(HashMap類與Hashtable大體相同,只是它不一樣步並容許空值。)
這個類不能保證順序;並且,它不能保證順序會隨着時間的推移保持不變。
非同步的
(2)Hashtable
這個類實現了一個哈希表,它將鍵映射到值。任何非空對象均可以用做鍵或值。
要成功地從哈希表存儲和檢索對象,用做鍵的對象必須實現hashCode方法和equals方法。
一個Hashtable的實例有兩個影響其性能的參數:初始容量和負載因子
容量是哈希表中桶的數量,初始容量就是哈希表建立時的容量。
一般,默認的加載因子(.75)在時間和空間成本之間提供了一個很好的折衷。
從Java 2平臺v1.2開始,該類被改型爲實現Map接口,使其成爲Java集合框架的成員。
與新的集合實現不一樣,Hashtable是同步的。
若是不須要線程安全的實現,建議使用HashMap來代替Hashtable。
若是須要線程安全的高度並行實現,則建議使用ConcurrentHashMap代替Hashtable。
(3)LinkedHashMap
Map 接口的哈希表和連接列表實現,具備可預知的迭代順序。
此實現與 HashMap 的不一樣之處在於,後者維護着一個運行於全部條目的雙重連接列表。
此連接列表定義了迭代順序,該迭代順序一般就是將鍵插入到映射中的順序(插入順序)。
注意,若是在映射中從新插入 鍵,則插入順序不受影響。
(若是在調用 m.put(k, v) 前 m.containsKey(k) 返回了 true,則調用時會將鍵 k 從新插入到映射 m 中。)
(3)TreeMap
基於紅黑樹(Red-Black tree)的 NavigableMap 實現。
該映射根據其鍵的天然順序進行排序,或者根據建立映射時提供的 Comparator 進行排序,具體取決於使用的構造方法。
此實現爲 containsKey、get、put 和 remove 操做提供受保證的 log(n) 時間開銷。
這些算法是 Cormen、Leiserson 和 Rivest 的 Introduction to Algorithms 中的算法的改編。
此實現不是同步的
(4)WeakHashMap
以弱鍵 實現的基於哈希表的 Map。
在 WeakHashMap 中,當某個鍵再也不正常使用時,將自動移除其條目。
更精確地說,對於一個給定的鍵,其映射的存在並不阻止垃圾回收器對該鍵的丟棄,這就使該鍵成爲可終止的,被終止,而後被回收。
丟棄某個鍵時,其條目從映射中有效地移除,所以,該類的行爲與其餘的 Map 實現有所不一樣。
null 值和 null 鍵都被支持。該類具備與 HashMap 類類似的性能特徵,並具備相同的效能參數初始容量 和加載因子。
像大多數 collection 類同樣,該類是不一樣步的。可使用 Collections.synchronizedMap 方法來構造同步的 WeakHashMap。
(5)EnumMap
與枚舉類型鍵一塊兒使用的專用 Map 實現。
枚舉映射中全部鍵都必須來自單個枚舉類型,該枚舉類型在建立映射時顯式或隱式地指定。
枚舉映射在內部表示爲數組。此表示形式很是緊湊且高效。
(6)IdentityHashMap
此類利用哈希表實現 Map 接口,比較鍵(和值)時使用引用相等性代替對象相等性。
換句話說,在 IdentityHashMap 中,當且僅當 (k1==k2) 時,才認爲兩個鍵 k1 和 k2 相等
(在正常 Map 實現(如 HashMap)中,當且僅當知足下列條件時才認爲兩個鍵 k1 和 k2 相等:(k1==null ? k2==null : e1.equals(e2)))。
此類不是 通用 Map 實現!
此類實現 Map 接口時,它有意違反 Map 的常規協定,該協定在比較對象時強制使用 equals 方法。此類設計僅用於其中須要引用相等性語義的罕見狀況。
基於併發編程的特性
又延伸出來下面這些接口:
java.util.concurrent包中
隊列Queue中:
阻塞隊列 BlockingQueue--生產者向隊列添加元素但隊列已滿時,生產者會被阻塞;當消費者從隊列移除元素但隊列爲空時,消費者會被阻塞
雙端的阻塞隊列 BlockingDeque
阻塞隊列又細分出來的概念TransferQueue
比BlockingQueue更進一步:
生產者會一直阻塞直到所添加到隊列的元素被某一個消費者所消費(不只僅是添加到隊列裏就完事)。
新添加的transfer方法用來實現這種約束。
顧名思義,阻塞就是發生在元素從一個線程transfer到另外一個線程的過程當中,它有效地實現了元素在線程之間的傳遞
Map中:
ConcurrentMap 接口表明一個Map,它能夠處理併發訪問。
ConcurrentMap除了繼承自java.util.Map的方法,還有一些本身的原子方法。
ConcurrentNavigableMap支持 NavigableMap 操做,且以遞歸方式支持其可導航子映射的 ConcurrentMap。
併發相關實現類 java.util.concurrent:
LinkedBlockingQueue
ArrayBlockingQueue
PriorityBlockingQueue
DelayQueue
SynchronousQueue
LinkedBlockingDeque
LinkedTransferQueue
CopyOnWriteArrayList
CopyOnWriteArraySet
ConcurrentSkipListSet
ConcurrentHashMap
ConcurrentSkipListMap
ConcurrentLinkedDeque
ConcurrentLinkedQueue
Iterable:
實現這個接口容許對象成爲 "foreach" 語句的目標。
實現了這個接口就代表已經聽從"迭代定義的規則",擁有了迭代的能力.
他是一個頂級接口:
其中:
/** * Returns an iterator over elements of type {@code T}. * * @return an Iterator. */ Iterator<T> iterator();
Iterator:
public interface Iterator<E>
想要有迭代的能力,
須要實現Iterable接口
實現接口最重要的就是提供一個 iterator() 方法,用於返回迭代器
首先,集合自己並非迭代器,他只是有能夠迭代的功能,因此是組合關係.
並且,若是繼承的話,那麼集合框架中:
Iterator接口的核心方法next()或者hasNext()
集合對象中就會包含當前迭代位置的數據(指針)
當集合在不一樣方法間被傳遞時,因爲當前迭代位置不可預置,那麼next()方法的結果會變成不可預知
RandomAccess
標記接口
/ * * @since 1.4 */ public interface RandomAccess { }
用來代表其支持快速(一般是固定時間)隨機訪問。
主要目的是使算法可以在隨機和順序訪問的list中表現的更加高效。
此接口的主要目的是容許通常的算法更改其行爲,從而在將其應用到隨機或連續訪問列表時能提供良好的性能。
好比:
Collections下的binarySearch方法的源碼:
public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c) { if (c==null) return binarySearch((List<? extends Comparable<? super T>>) list, key); if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD) return Collections.indexedBinarySearch(list, key, c); else return Collections.iteratorBinarySearch(list, key, c); }
從中能夠清晰的看到,這個RandomAccess標記的做用
java集合框架中的全部具體類中都實現了Cloneable和Serializable接口
所以它們的實例都是可複製且可序列化的。
Serializable
public interface Serializable { }