Java集合【6】——— Collection接口源碼解析

[TOC]

一、Collection接口簡(jiǎn)介

collection在java集合中,算是頂級(jí)接口,它繼承了iterable接口,不能實(shí)例化,只能實(shí)例化其子類。之所以需要這樣一個(gè)接口,是因?yàn)閖ava作為面向?qū)ο?,總是避免不了處理多個(gè)對(duì)象的情況,要處理多個(gè)對(duì)象,首先需要容器存儲(chǔ),這個(gè)容器就是集合。為什么有了數(shù)組,還需要集合,因?yàn)閿?shù)組的功能單一,長(zhǎng)度不可變,而有些集合實(shí)現(xiàn)類則是對(duì)數(shù)組操作的封裝。

Collection集合和數(shù)組的區(qū)別:

  • 集合長(zhǎng)度可以變,數(shù)組是定長(zhǎng)的
  • 集合存儲(chǔ)的元素只能是引用類型,而數(shù)組則可以是基本類型
  • 數(shù)組只能執(zhí)行基本操作,而集合功能經(jīng)過拓展,更加豐富。
graph TD;
Collection -->List-有順序,可重復(fù) 
List-有順序,可重復(fù)  -->LinkedList-使用鏈表實(shí)現(xiàn),線程不安全
List-有順序,可重復(fù)  -->ArrayList-數(shù)組實(shí)現(xiàn),線程不安全
List-有順序,可重復(fù)  -->Vector-數(shù)組實(shí)現(xiàn),線程安全
Vector-數(shù)組實(shí)現(xiàn),線程安全 -->Stack-堆棧,先進(jìn)后出

Collection-->Set-不可重復(fù),內(nèi)部排序
Set-不可重復(fù),內(nèi)部排序-->HashSet-hash表存儲(chǔ)
HashSet-hash表存儲(chǔ)-->LinkHashSet-鏈表維護(hù)插入順序
Set-不可重復(fù),內(nèi)部排序-->TreeSet-二叉樹實(shí)現(xiàn),排序

Collection-->Queue-隊(duì)列,先進(jìn)先出

二、Collection源碼分析

Collection繼承于Iterable接口,而Iterable接口,是集合的頂級(jí)接口,沒有之一,Iterable接口定義的功能是可以迭代,也就是獲取迭代器iterator的功能,因此Collection以及其實(shí)現(xiàn)類也間接獲得迭代的功能。

為什么需要這樣子定義呢?我陷入了深深地思考...??

其實(shí),這也算是哲學(xué)問題,java的類的設(shè)計(jì)是經(jīng)過很長(zhǎng)時(shí)間的考驗(yàn)以及調(diào)整形成的,平衡修改以及耦合等各方面的原因,結(jié)構(gòu)更加清晰,維護(hù)成本更低,邏輯性更強(qiáng)。這些接口就是一個(gè)個(gè)標(biāo)準(zhǔn)或者規(guī)范,其子類就是不斷拓展功能,這些接口的形成是一種抽象,將能迭代事物抽象成為迭代器iterator,將獲取迭代器,也就是迭代能力抽象成iterable。
Collection則是獲得迭代能力的接口之一,其實(shí)Map的實(shí)現(xiàn)類里面也是有使用到iterable接口,幾乎所有的集合實(shí)現(xiàn)類都是需要遍歷元素的,所以這個(gè)iterable也是必須存在的,存在即合理。

下面看Collection接口以及iterable接口的方法對(duì)比:

image

從上面的圖我們可以看出,iterable接口功能主要是

  • 獲取迭代器iterator
  • foreach()遍歷
  • 獲取可切分迭代器Spliterator

Collection接口在此基礎(chǔ)上進(jìn)行拓展,源碼接口如下:

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<E> iterator()    // 獲取迭代器

Object[] toArray()    // 轉(zhuǎn)成數(shù)組

default boolean removeIf(Predicate<? super E> filter) {} // 刪除集合中復(fù)合條件的元素,刪除成功返回true

boolean equals(Object o)

int hashCode()

default Spliterator<E> spliterator() {} //獲取可分割迭代器

default Stream<E> stream() {}   //獲取流

default Stream<E> parallelStream() {} //獲取并行流

里面獲取并行流的方法parallelStream(),其實(shí)就是通過默認(rèn)的ForkJoinPool(主要用來使用分治法(Divide-and-Conquer Algorithm)來解決問題),提高多線程任務(wù)的速度。我們可以使用ArrayList來演示一下平行處理能力。例如下面的例子,輸出的順序就不一定是1,2,3...,可能是亂序的,這是因?yàn)槿蝿?wù)會(huì)被分成多個(gè)小任務(wù),任務(wù)執(zhí)行是沒有特定的順序的。

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
list.parallelStream()
       .forEach(out::println);

上面源代碼可以看出,Collection接口定義了功能規(guī)范,有以下功能方法:

  • 添加元素
  • 刪除元素
  • 判斷是否包含/是否全部包含/是否為空
  • 獲取迭代器/可分割迭代器
  • 獲取長(zhǎng)度
  • 取交集
  • 獲取流/并行流

我們遍歷元素的時(shí)候可以獲取Iterator,但是具體的實(shí)現(xiàn)是以子類的特性去實(shí)現(xiàn)的,比如ArrayList是用內(nèi)部類的方式實(shí)現(xiàn)了Iterator接口。

三、Collection的子類以及子類的實(shí)現(xiàn)

繼承Collection的子類關(guān)系如下:

image

上面的類圖已經(jīng)足夠清楚,下面是一些簡(jiǎn)單的概括(上面的類型是使用IDEA的類圖功能自動(dòng)生成,簡(jiǎn)直不能太好用??????感覺發(fā)現(xiàn)了新大陸)

3.1 List extend Collection<E>

繼承于Collection接口,有順序,取出的順序與存入的順序一致,有索引,可以根據(jù)索引獲取數(shù)據(jù),允許存儲(chǔ)重復(fù)的元素,可以放入為null的元素。
最常見的三個(gè)實(shí)現(xiàn)類就是ArrayList,Vector,LinkedListArrayListVector都是內(nèi)部封裝了對(duì)數(shù)組的操作,唯一不同的是,Vector是線程安全的,而ArrayList不是,理論上ArrayList操作的效率會(huì)比Vector好一些。

里面是接口定義的方法:

int size();  //獲取大小

boolean isEmpty();  //判斷是否為空

boolean contains(Object o);  //是否包含某個(gè)元素

Iterator<E> iterator(); //獲取迭代器

Object[] toArray();  // 轉(zhuǎn)化成為數(shù)組(對(duì)象)

<T> T[] toArray(T[] a);  // 轉(zhuǎn)化為數(shù)組(特定位某個(gè)類)

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<E> operator) {}//替換

default void sort(Comparator<? super E> c) {}// 排序

void clear();//清除所有的元素

boolean equals(Object o);//是否相等

int hashCode(); //計(jì)算獲取hash值

E get(int index); //通過索引獲取元素

E set(int index, E element);//修改元素

void add(int index, E element);//在指定位置插入元素

E remove(int index);//根據(jù)索引移除某個(gè)元素

int indexOf(Object o);  //根據(jù)對(duì)象獲取索引

int lastIndexOf(Object o); //獲取對(duì)象元素的最后一個(gè)元素

ListIterator<E> listIterator(); // 獲取List迭代器

ListIterator<E> listIterator(int index); // 根據(jù)索引獲取當(dāng)前的位置的迭代器

List<E> subList(int fromIndex, int toIndex); //截取某一段數(shù)據(jù)

default Spliterator<E> spliterator(){} //獲取可切分迭代器

上面的方法都比較簡(jiǎn)單,值得一提的是里面出現(xiàn)了ListIterator,這是一個(gè)功能更加強(qiáng)大的迭代器,繼承于Iterator,只能用于List類型的訪問,拓展功能例如:通過調(diào)用listIterator()方法獲得一個(gè)指向List開頭的ListIterator,也可以調(diào)用listIterator(n)獲取一個(gè)指定索引為n的元素的ListIterator,這是一個(gè)可以雙向移動(dòng)的迭代器。
操作數(shù)組索引的時(shí)候需要注意,由于List的實(shí)現(xiàn)類底層很多都是數(shù)組,所以索引越界會(huì)報(bào)錯(cuò)IndexOutOfBoundsException。
說起List的實(shí)現(xiàn)子類:

  • ArrayList:底層存儲(chǔ)結(jié)構(gòu)是數(shù)組結(jié)構(gòu),增加刪除比較慢,查找比較快,是最常用的List集合。線程不安全。
  • LinkedList:底層是鏈表結(jié)構(gòu),增加刪除比較快,但是查找比較慢。線程不安全。
  • Vector:和ArrayList差不多,但是是線程安全的,即同步。

3.2 Set extend Collection<E>

Set接口,不允許放入重復(fù)的元素,也就是如果相同,則只存儲(chǔ)其中一個(gè)。

image

下面是源碼方法:

int size(); //獲取大小

boolean isEmpty();  //是否為空
 
boolean contains(Object o); //是否包含某個(gè)元素

Iterator<E> iterator(); //獲取迭代器

Object[] toArray(); //轉(zhuǎn)化成為數(shù)組

<T> T[] toArray(T[] a); //轉(zhuǎn)化為特定類的數(shù)組

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(); //計(jì)算hashcode

default Spliterator<E> spliterator() {}     //獲取可分割迭代器
        

主要的子類:

  • HashSet
    • 允許空值
    • 通過HashCode方法計(jì)算獲取hash值,確定存儲(chǔ)位置,無序。
    • 底層是哈希表,一個(gè)元素為鏈表的數(shù)組
  • LinkedHashSet
    • HashSet的子類
    • 有順序
    • 底層由哈希表組成
  • TreeSet
    • 如果無參數(shù)構(gòu)建Set,則需要實(shí)現(xiàn)Comparable方法。
    • 亦可以創(chuàng)建時(shí)傳入比較方法,用于排序。

3.3 Queue extend Collection<E>

隊(duì)列接口,在Collection接口的接觸上添加了增刪改查接口定義,一般默認(rèn)是先進(jìn)先出,即FIFO,除了優(yōu)先隊(duì)列和棧,優(yōu)先隊(duì)列是自己定義了排序的優(yōu)先順序,隊(duì)列中不允許放入null元素。

image

下面是源碼:

boolean add(E e);   //插入一個(gè)元素到隊(duì)列,失敗時(shí)返回IllegalStateException (如果隊(duì)列容量不夠)

boolean offer(E e); //插入一個(gè)元素到隊(duì)列,失敗時(shí)返回false

E remove(); //移除隊(duì)列頭的元素并移除

E poll();   //返回并移除隊(duì)列的頭部元素,隊(duì)列為空時(shí)返回null

E element();    //返回隊(duì)列頭元素

E peek();   //返回隊(duì)列頭部的元素,隊(duì)列為空時(shí)返回null

主要的子接口以及實(shí)現(xiàn)類有:

image
  • Deque(接口):Queue的子接口,雙向隊(duì)列,可以從兩邊存取
    • ArrayDeque:Deque的實(shí)現(xiàn)類,底層用數(shù)組實(shí)現(xiàn),數(shù)據(jù)存貯在數(shù)組中
  • AbstractQueue:Queue的子接口,僅實(shí)現(xiàn)了add、remove和element三個(gè)方法
    • PriorityQueue:按照默認(rèn)或者自己定義的順序來排序元素,底層使用堆(完全二叉樹)實(shí)現(xiàn),使用動(dòng)態(tài)數(shù)組實(shí)現(xiàn),
  • BlockingQueue: 在java.util.concurrent包中,阻塞隊(duì)列,滿足當(dāng)前無法處理的操作。

對(duì)于Collection集合我們應(yīng)該使用哪一個(gè)?

每個(gè)實(shí)現(xiàn)都有自己的特點(diǎn),重要的是知道當(dāng)前數(shù)據(jù)以及業(yè)務(wù)的特點(diǎn),選取最適合的集合類進(jìn)行數(shù)據(jù)操作。

  • 元素唯一(Set)
    • 需要排序
      • 唯一,有序 (自定義排序):TreeSet(速度較慢)
      • FIFO,按照插入順序,唯一:LinkedHashSet(速度較快)
    • 不需要排序:HashSet(速度最快)
  • 元素唯一
    • 列表:List
      • 線程安全:Vector
      • 接受線程不安全
        • 查詢比較多:ArrayList
        • 增加刪除操作較多:LinkedList
    • 排隊(duì)
      • 普通排隊(duì) :Queue的子類
      • 兩端都可以排隊(duì):ArrayDeque
      • 按照自己定義的規(guī)則排序:PriorityQueue
      • 處理排隊(duì)當(dāng)前無法處理太多請(qǐng)求(相當(dāng)于緩沖):阻塞隊(duì)列接口BlockingQueue

四、Collection和Map的辨析

  • Collection接口是存儲(chǔ)單列元素,而Map是鍵值對(duì)<Key,Value>,也就是存儲(chǔ)了雙列元素。
  • Collection接口繼承了Iterable接口,而Map則不是,Map是在各自的實(shí)現(xiàn)類中才用內(nèi)部類的方式實(shí)現(xiàn)Iterator接口,例如HashMap,key或者value或者它們的組合entry都可以使用迭代器進(jìn)行遍歷。
  • 兩個(gè)的子類其實(shí)是有交集的,比如HashSet的底層實(shí)現(xiàn)其實(shí)就是定義了一個(gè)HashMap,TreeSet同樣依賴于Map接口的子實(shí)現(xiàn)類TreeMap

Map集合可以存儲(chǔ)鍵值對(duì),可以獲取所有的鍵,或者值或者鍵值對(duì),鍵不允許重復(fù),但是值可以重復(fù)。
隨便說說Map相關(guān)的子類:

  • HashTable:
    • 源于JDK1.1,底層使用數(shù)組和鏈表
    • 線程安全,不允許null作為key或者value
  • HashMap:
    • 源于JDK1.2,JDK1.7以及之前使用數(shù)組+鏈表實(shí)現(xiàn),JDK1.8使用數(shù)組+鏈表/紅黑樹
    • 線程不安全
  • LinkedHashMap:
    • 保存了插入的順序,可以按照順序遍歷
  • TreeMap:
    • 實(shí)現(xiàn)了SortMap接口,可以把保存的記錄按照鍵排序
    • 底層是用紅黑樹實(shí)現(xiàn)

五、Collection和Collections的辨析

(1).Collection是集合的頂級(jí)接口之一,衍生出了SetList,Queue等一系列接口以及實(shí)現(xiàn)類。而Collections是一個(gè)輔助類,就是實(shí)現(xiàn)一些排序,搜索,線程安全等功能,它主要體現(xiàn)的功能是操作集合,而Collection則是集合本身。

(2).Collection是接口,其本身不能實(shí)例化,但是可以實(shí)例化為其子類或者實(shí)現(xiàn)類,但是Collections是包裝類,一般不會(huì)實(shí)例化,直接調(diào)用static方法。

Collections接口主要提供了以下操作,只展示了部分,詳細(xì)需要后面文章說:

  1. Sort(排序):public static <T extends Comparable<? super T>> void sort(List<T> list),元素需要實(shí)現(xiàn)Comparable接口,按照比較器進(jìn)行排序。
  2. binarySearch(二分搜索):public static <T>int binarySearch(List<? extends Comparable<? super T>> list, T key),
  3. reverse(反轉(zhuǎn)):public static void reverse(List<?> list)反轉(zhuǎn)順序
  4. Shuffling(混排):public static void shuffle(List<?> list),將list的元素隨機(jī)打亂。
  5. 交換(swap):public static void swap(List<?> list, int i, int j)交換兩個(gè)索引的元素
  6. 拷貝(copy):public static <T> void copy(List<? super T> dest, List<? extends T> src),copy出一個(gè)內(nèi)容一致的list。
  7. 返回最小的元素(min):所謂大小,根據(jù)指定的比較器決定,static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
  8. 返回最大的元素(max):static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
  9. 旋轉(zhuǎn)(Rotate):將一個(gè)List旋轉(zhuǎn),假如有個(gè)序列列l(wèi)ist是[1,2,3,4],調(diào)用方法Collections.rotate(list, 1)后,得到list就變成[4,1,2,3],public static void rotate(List<?> list, int distance)
  10. 替換所有元素(replaceAll):public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal)
  11. 獲取元素出現(xiàn)最后的索引(lastIndexOfSubList):public static int lastIndexOfSubList(List<?> source, List<?> target)

六、總結(jié)

Collection接口繼承了iterable接口,是集合的頂級(jí)接口之一,衍生接口有List,Set,Queue等,主要定義了元素的基本操作,刪除,添加等等方法,迭代一個(gè)Collection可以使用Iterator,但是Collection本身不能實(shí)例化。
此文章僅代表自己(本菜鳥)學(xué)習(xí)積累記錄,或者學(xué)習(xí)筆記,如有侵權(quán),請(qǐng)聯(lián)系作者刪除。人無完人,文章也一樣,文筆稚嫩,在下不才,勿噴,如果有錯(cuò)誤之處,還望指出,感激不盡~

技術(shù)之路不在一時(shí),山高水長(zhǎng),縱使緩慢,馳而不息。

公眾號(hào):秦懷雜貨店

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容