2接口详解_java集合【2】——— Collection接口详解
一、Collection接口簡介
二、Collection源碼分析
三、Collection的子類以及子類的實現
3.1 List extend Collection
3.2 Set extend Collection
3.3 Queue extend Collection
四、Collection和Map的辨析
五、Collection和Collections的辨析
六、總結
一、Collection接口簡介
collection在java集合中,算是頂級接口,它繼承了iterable接口,不能實例化,只能實例化其子類。之所以需要這樣一個接口,是因為java作為面向對象,總是避免不了處理多個對象的情況,要處理多個對象,首先需要容器存儲,這個容器就是集合。為什么有了數組,還需要集合,因為數組的功能單一,長度不可變,而有些集合實現類則是對數組操作的封裝。
Collection集合和數組的區別:
- 集合長度可以變,數組是定長的
- 集合存儲的元素只能是引用類型,而數組則可以是基本類型
- 數組只能執行基本操作,而集合功能經過拓展,更加豐富。
Collection -->List-有順序,可重復
List-有順序,可重復 -->LinkedList-使用鏈表實現,線程不安全
List-有順序,可重復 -->ArrayList-數組實現,線程不安全
List-有順序,可重復 -->Vector-數組實現,線程安全
Vector-數組實現,線程安全 -->Stack-堆棧,先進后出
Collection-->Set-不可重復,內部排序
Set-不可重復,內部排序-->HashSet-hash表存儲
HashSet-hash表存儲-->LinkHashSet-鏈表維護插入順序
Set-不可重復,內部排序-->TreeSet-二叉樹實現,排序
Collection-->Queue-隊列,先進先出
二、Collection源碼分析
Collection繼承于Iterable接口,而Iterable接口,是集合的頂級接口,沒有之一,Iterable接口定義的功能是可以迭代,也就是獲取迭代器iterator的功能,因此Collection以及其實現類也間接獲得迭代的功能。
為什么需要這樣子定義呢?我陷入了深深地思考...?
其實,這也算是哲學問題,java的類的設計是經過很長時間的考驗以及調整形成的,平衡修改以及耦合等各方面的原因,結構更加清晰,維護成本更低,邏輯性更強。這些接口就是一個個標準或者規范,其子類就是不斷拓展功能,這些接口的形成是一種抽象,將能迭代事物抽象成為迭代器iterator,將獲取迭代器,也就是迭代能力抽象成iterable。Collection則是獲得迭代能力的接口之一,其實Map的實現類里面也是有使用到iterable接口,幾乎所有的集合實現類都是需要遍歷元素的,所以這個iterable也是必須存在的,存在即合理。
下面看Collection接口以及iterable接口的方法對比:從上面的圖我們可以看出,iterable接口功能主要是
- 獲取迭代器iterator
- foreach()遍歷
- 獲取可切分迭代器Spliterator
Collection接口在此基礎上進行拓展,源碼接口如下:
boolean?add(Object?o)????//添加元素boolean?remove(Object?o)??//移除元素boolean?addAll(Collection?c)?//批量添加boolean?removeAll(Collection?c)??//批量移除void?retainAll(Collection?c)???//?移除在c中不存在的元素void?clear()??//清空集合int?size()???//集合大小boolean?isEmpty()????//是否為空boolean?contains(Object?o)????//是否包含在集合中boolean?containsAll(Collection?c)????//是否包含所有的元素Iterator?iterator()????//?獲取迭代器
Object[]?toArray()???//?轉成數組default?boolean?removeIf(Predicate?super?E>?filter)?{}?//?刪除集合中復合條件的元素,刪除成功返回true
boolean?equals(Object?o)int?hashCode()default?Spliterator?spliterator()?{}?//獲取可分割迭代器
default?Stream?stream()?{}???//獲取流
default?Stream?parallelStream()?{}?//獲取并行流
里面獲取并行流的方法parallelStream(),其實就是通過默認的ForkJoinPool(主要用來使用分治法(Divide-and-Conquer Algorithm)來解決問題),提高多線程任務的速度。我們可以使用ArrayList來演示一下平行處理能力。例如下面的例子,輸出的順序就不一定是1,2,3...,可能是亂序的,這是因為任務會被分成多個小任務,任務執行是沒有特定的順序的。
List?list?=?Arrays.asList(1,?2,?3,?4,?5,?6,?7,?8,?9);list.parallelStream()
???????.forEach(out::println);
上面源代碼可以看出,Collection接口定義了功能規范,有以下功能方法:
- 添加元素
- 刪除元素
- 判斷是否包含/是否全部包含/是否為空
- 獲取迭代器/可分割迭代器
- 獲取長度
- 取交集
- 獲取流/并行流
我們遍歷元素的時候可以獲取Iterator,但是具體的實現是以子類的特性去實現的,比如ArrayList是用內部類的方式實現了Iterator接口。
三、Collection的子類以及子類的實現
繼承Collection的子類關系如下:
上面的類圖已經足夠清楚,下面是一些簡單的概括(上面的類型是使用IDEA的類圖功能自動生成,簡直不能太好用???感覺發現了新大陸)
3.1 List extend Collection
繼承于Collection接口,有順序,取出的順序與存入的順序一致,有索引,可以根據索引獲取數據,允許存儲重復的元素,可以放入為null的元素。
最常見的三個實現類就是ArrayList,Vector,LinkedList,ArrayList和Vector都是內部封裝了對數組的操作,唯一不同的是,Vector是線程安全的,而ArrayList不是,理論上ArrayList操作的效率會比Vector好一些。
里面是接口定義的方法:
int?size();??//獲取大小boolean?isEmpty();??//判斷是否為空
boolean?contains(Object?o);??//是否包含某個元素
Iterator?iterator();?//獲取迭代器
Object[]?toArray();??//?轉化成為數組(對象)
?T[]?toArray(T[]?a);??//?轉化為數組(特定位某個類)boolean?add(E?e);?//添加boolean?remove(Object?o);??//移除元素boolean?containsAll(Collection>?c);?//?是否包含所有的元素boolean?addAll(Collection?extends?E>?c);?//批量添加boolean?addAll(int?index,?Collection?extends?E>?c);?//批量添加,指定開始的索引boolean?removeAll(Collection>?c);?//批量移除boolean?retainAll(Collection>?c);?//將c中不包含的元素移除default?void?replaceAll(UnaryOperator?operator)?{}//替換default?void?sort(Comparator?super?E>?c)?{}//?排序void?clear();//清除所有的元素boolean?equals(Object?o);//是否相等int?hashCode();?//計算獲取hash值E?get(int?index);?//通過索引獲取元素E?set(int?index,?E?element);//修改元素void?add(int?index,?E?element);//在指定位置插入元素E?remove(int?index);//根據索引移除某個元素int?indexOf(Object?o);??//根據對象獲取索引int?lastIndexOf(Object?o);?//獲取對象元素的最后一個元素ListIterator?listIterator();?//?獲取List迭代器ListIterator?listIterator(int?index);?//?根據索引獲取當前的位置的迭代器List?subList(int?fromIndex,?int?toIndex);?//截取某一段數據default?Spliterator?spliterator(){}?//獲取可切分迭代器
上面的方法都比較簡單,值得一提的是里面出現了ListIterator,這是一個功能更加強大的迭代器,繼承于Iterator,只能用于List類型的訪問,拓展功能例如:通過調用listIterator()方法獲得一個指向List開頭的ListIterator,也可以調用listIterator(n)獲取一個指定索引為n的元素的ListIterator,這是一個可以雙向移動的迭代器。
操作數組索引的時候需要注意,由于List的實現類底層很多都是數組,所以索引越界會報錯IndexOutOfBoundsException。
說起List的實現子類:
- ArrayList:底層存儲結構是數組結構,增加刪除比較慢,查找比較快,是最常用的List集合。線程不安全。
- LinkedList:底層是鏈表結構,增加刪除比較快,但是查找比較慢。線程不安全。
- Vector:和ArrayList差不多,但是是線程安全的,即同步。
3.2 Set extend Collection
Set接口,不允許放入重復的元素,也就是如果相同,則只存儲其中一個。
下面是源碼方法:
int?size();?//獲取大小boolean?isEmpty();??//是否為空
?
boolean?contains(Object?o);?//是否包含某個元素
Iterator?iterator();?//獲取迭代器
Object[]?toArray();?//轉化成為數組
?T[]?toArray(T[]?a);?//轉化為特定類的數組boolean?add(E?e);???//添加元素boolean?remove(Object?o);???//移除元素boolean?containsAll(Collection>?c);???//是否包含所有的元素boolean?addAll(Collection?extends?E>?c);??//批量添加boolean?retainAll(Collection>?c);?//移除所有不存在于c集合中的元素boolean?removeAll(Collection>?c);?//移除所有在c集合中存在的元素void?clear();???//清空集合boolean?equals(Object?o);???//是否相等int?hashCode();?//計算hashcodedefault?Spliterator?spliterator()?{}?????//獲取可分割迭代器
主要的子類:
- HashSet
- 允許空值
- 通過HashCode方法計算獲取hash值,確定存儲位置,無序。
- 底層是哈希表,一個元素為鏈表的數組
- LinkedHashSet
- HashSet的子類
- 有順序
- 底層由哈希表組成
- TreeSet
- 如果無參數構建Set,則需要實現Comparable方法。
- 亦可以創建時傳入比較方法,用于排序。
3.3 Queue extend Collection
隊列接口,在Collection接口的接觸上添加了增刪改查接口定義,一般默認是先進先出,即FIFO,除了優先隊列和棧,優先隊列是自己定義了排序的優先順序,隊列中不允許放入null元素。
下面是源碼:
boolean?add(E?e);???//插入一個元素到隊列,失敗時返回IllegalStateException?(如果隊列容量不夠)boolean?offer(E?e);?//插入一個元素到隊列,失敗時返回false
E?remove();?//移除隊列頭的元素并移除
E?poll();???//返回并移除隊列的頭部元素,隊列為空時返回null
E?element();????//返回隊列頭元素
E?peek();???//返回隊列頭部的元素,隊列為空時返回null
主要的子接口以及實現類有:
- Deque(接口):Queue的子接口,雙向隊列,可以從兩邊存取
- ArrayDeque:Deque的實現類,底層用數組實現,數據存貯在數組中
- AbstractQueue:Queue的子接口,僅實現了add、remove和element三個方法
- PriorityQueue:按照默認或者自己定義的順序來排序元素,底層使用堆(完全二叉樹)實現,使用動態數組實現,
- BlockingQueue:在java.util.concurrent包中,阻塞隊列,滿足當前無法處理的操作。
對于Collection集合我們應該使用哪一個?
每個實現都有自己的特點,重要的是知道當前數據以及業務的特點,選取最適合的集合類進行數據操作。
- 元素唯一(Set)
- 唯一,有序 (自定義排序):TreeSet(速度較慢)
- FIFO,按照插入順序,唯一:LinkedHashSet(速度較快)
- 需要排序
- 不需要排序:HashSet(速度最快)
- 元素唯一
- 普通排隊 :Queue的子類
- 兩端都可以排隊:ArrayDeque
- 按照自己定義的規則排序:PriorityQueue
- 處理排隊當前無法處理太多請求(相當于緩沖):阻塞隊列接口BlockingQueue
- 線程安全:Vector
- 接受線程不安全
- 查詢比較多:ArrayList
- 增加刪除操作較多:LinkedList
- 列表:List
- 排隊
四、Collection和Map的辨析
- Collection接口是存儲單列元素,而Map是鍵值對,也就是存儲了雙列元素。
- Collection接口繼承了Iterable接口,而Map則不是,Map是在各自的實現類中才用內部類的方式實現Iterator接口,例如HashMap,key或者value或者它們的組合entry都可以使用迭代器進行遍歷。
- 兩個的子類其實是有交集的,比如HashSet的底層實現其實就是定義了一個HashMap,TreeSet同樣依賴于Map接口的子實現類TreeMap。
Map集合可以存儲鍵值對,可以獲取所有的鍵,或者值或者鍵值對,鍵不允許重復,但是值可以重復。隨便說說Map相關的子類:
- HashTable:
- 源于JDK1.1,底層使用數組和鏈表
- 線程安全,不允許null作為key或者value
- HashMap:
- 源于JDK1.2,JDK1.7以及之前使用數組+鏈表實現,JDK1.8使用數組+鏈表/紅黑樹
- 線程不安全
- LinkedHashMap:
- 保存了插入的順序,可以按照順序遍歷
- TreeMap:
- 實現了SortMap接口,可以把保存的記錄按照鍵排序
- 底層是用紅黑樹實現
五、Collection和Collections的辨析
(1).Collection是集合的頂級接口之一,衍生出了Set,List,Queue等一系列接口以及實現類。而Collections是一個輔助類,就是實現一些排序,搜索,線程安全等功能,它主要體現的功能是操作集合,而Collection則是集合本身。
(2).Collection是接口,其本身不能實例化,但是可以實例化為其子類或者實現類,但是Collections是包裝類,一般不會實例化,直接調用static方法。
Collections接口主要提供了以下操作,只展示了部分,詳細需要后面文章說:
六、總結
Collection接口繼承了iterable接口,是集合的頂級接口之一,衍生接口有List,Set,Queue等,主要定義了元素的基本操作,刪除,添加等等方法,迭代一個Collection可以使用Iterator,但是Collection本身不能實例化。
- END -總結
以上是生活随笔為你收集整理的2接口详解_java集合【2】——— Collection接口详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小批量随机梯度下降
- 下一篇: 干货|MIT线性代数课程精细笔记5