1. 程式人生 > >Java集合原始碼分析02----Collection集合

Java集合原始碼分析02----Collection集合

目錄

 

Collection框架綜述

Collection介面

Set介面

List介面

Queue介面

迭代器


-----------參考《Thank In Java》

Collection框架綜述

Collection是一個介面,分為常見的兩部分:List和Set,以及在併發程式設計常用的Queue.

其中AbstractCollection抽象類實現了介面Collection中大部分的方法,AbstractList和AbstractSet兩個抽象類又直接繼承了AbstractCollection,而基本上所有的List和Set介面實現類都分別繼承AbstractList和AbstractSet類,這樣減少實現類中程式碼的重複,而Queue介面的大部分實現類繼承了AbstractCollection。

List集合特點是元素是有序的,並且允許元素重複;Set集合不能有重複的元素;Queue按照排隊規則來確定物件輸出的順序(通常與它們被插入的順序相同)。

Collection介面

Collection介面是Collection繼承體系中根介面,定義了獲取集合大小,新增元素,刪除元素,清空,判空以及迭代元素的迭代器等方法。

//返回當前儲存到集合中元素個數
int size(); 
//collection中不包含任何元素,返回true
boolean isEmpty();
//collection包含了指定了元素,返回true.
boolean contains(Object o);
//返回一個用於訪問集合中每個元素的迭代器
Iterator<E> iterator();
//返回包含collection所有元素的陣列
Object[] toArray();
//返回包含collection所有元素的陣列,並且指定了陣列的型別
<T> T[] toArray(T[] a);
//新增指定的元素,返回是否新增成功
boolean add(E e);
//移除指定的元素,返回是否移除成功
boolean remove(Object o);
//判斷collection裡面是否包含集合c中所有元素
boolean containsAll(Collection<?> c);
//將集合c中所有元素新增到collection中
boolean addAll(Collection<? extends E> c);
//移除collection中那些也包含在集合c中元素
boolean removeAll(Collection<?> c);
//保留此collection中那些在集合c中包含的元素
boolean retainAll(Collection<?> c);
//移除此collection中的所有元素
void clear();
//collection與指定物件o是否相等
boolean equals(Object o);
//返回此collection的hashcode值
int hashCode();
//jdk1.8中加入的內容
default Spliterator<E> spliterator() {}
default Stream<E> stream() {}
default Stream<E> parallelStream() {}
default boolean removeIf(Predicate<? super E> filter) {}

Set介面

Set介面中的方法與Collection完全一樣的,沒有新增任何的額外的功能。實際上Set就是Collection,只是表現了不同的行為(是多型與繼承的典型應用)。Set不會儲存重複的元素,允許儲存null,並且只能有一個。

Set介面常見的實現類:

1)HashSet:使用雜湊函式的儲存方式,HashSet按照雜湊演算法來儲存集合的元素,具有很好的存取和查詢效能,非執行緒安全的。HashSet依賴HashMap實現的,集合中元素是無序的(元素插入和輸出的順序不一致)。HashSet主要是為了快速查詢而設計的,存入HashSet的元素必須要定義HashCode()方法。

2)LinkedHashSet:繼承自HashSet,底層依賴LinkedHashMap實現的, 使用了雜湊函式 ,但LinkedHashSet使用了連結串列來維護元素的插入位置,所以集合中元素是有序的,可以按照元素的新增順序來訪問集合中的元素。

3)TreeSet:將元素儲存在了紅黑數資料結構中,繼承自SortedSet介面,儲存到TreeSet中的元素需要實現Comparable介面,重寫CompareTo()方法,TreeSet會按照排序順序維護元素(即CompareTo()實現方式,如降序或者升序)。

4)EnumSet是列舉型別元素集合的高效實現,由於列舉型別只有有限個個數,所以EnumSet內部用位序列(位向量)實現。這種儲存形式比較高效,佔用記憶體比較小,執行效率比較好。EnumSet提供了很多便捷的靜態方法。

List介面

List介面繼承自Collection介面,在Collection的基礎上添加了其他方法,包含在指定索引位置上新增元素,刪除元素,替換元素,獲取元素的索引位置以及迭代List集合的迭代器等方法。List可以儲存重複的元素,允許儲存多個null。List集合是有序的,集合中每個元素都有其對應的索引位置,可以通過索引位置來訪問指定位置的元素,第一個索引位置是0。

Collection介面中方法省略
...
//返回list中指定索引的元素
E get(int index);
//用指定的元素替換指定索引上的元素
E set(int index, E element);
//list指定索引上插入指定元素
void add(int index, E element);
//新增集合c中的元素到list指定的索引
boolean addAll(int index, Collection<? extends E> c);
//移除list中指定索引上元素
E remove(int index);
//返回list中第一次出現指定元素的索引,如果不包含該元素,將返回-1.
int indexOf(Object o);
//返回list中最後出現的指定元素的索引,如果不包含該元素,將返回-1.
int lastIndexOf(Object o);
//返回此list的元素迭代的迭代器.
ListIterator<E> listIterator();
//返回此list的元素的迭代的迭代器,從指定位置開始.
ListIterator<E> listIterator(int index);
//返回從list的fromIndex(包含)到toIndex(不包含)之間的元素
List<E> subList(int fromIndex, int toIndex);
//jdk1.8新增的內容
default void replaceAll(UnaryOperator<E> operator)
default void sort(Comparator<? super E> c)

List介面的實現類常見有如下:

1)ArrayList:底層是一個動態陣列,隨機訪問速度比較快,但是在ArrayList中插入和移除元素時較慢。它是非執行緒安全的。

2)LinkedList:繼承了Deque介面,底層是一個雙向連結串列的結構,在LinkedList中插入和刪除元素代價比較低(這點比ArrayList更加高效),但隨即訪問操作方面效率比較低。經常被當做堆疊,佇列或者雙端佇列使用,它是非執行緒安全的。

3)Vector:與ArrayList一樣,底層也是動態陣列,但是Vector是執行緒安全的,並且Vector相比ArrayList,沒有實現java.io.Serializable介面,所以不支援序列化。

4)Stack:是“棧”,繼承自Vector,是先進後出(LIFO)的容器(有時稱為疊加棧),即壓人棧的第一個元素,最後一個彈出棧。

Queue介面

Queue,即佇列,是一個典型先進先出的容器(FIFO),即從容器的一端放入元素,然後從另外一端取出元素。放入佇列中的順序與取出元素的順序是一樣的。佇列在併發程式設計中比較重要。

//向佇列中插入指定的元素,成功返回true,如果沒有空間將丟擲異常
boolean add(E e);
//向佇列中插入指定的元素
boolean offer(E e);
//移除佇列頭部的元素,佇列我空時將丟擲異常
E remove();
//移除佇列頭部的元素,佇列為空時返回null
E poll();
//獲取佇列頭部的元素,佇列為空時將丟擲異常
E element();
//獲取佇列頭部的元素,佇列為空時返回null
E peek();

關於Queue介面中幾個方法在操作失敗時差異說明:

1)add(e),remove(),element()方法在對集合操作失敗時將會丟擲異常。

2)offer(e),poll(),peek()方法在對集合操作失敗時將返回特殊值。

佇列操作 丟擲異常(失敗情況下) 返回特殊值(失敗情況下)
插入 add(e) offer(e)
移除 remove() poll()
檢查 element() peek()

1)PriorityQueue:並不是一個標準的先進先出的佇列,先進先出佇列規則表明了下一個元素應該是等待時間最長的元素。但PriorityQueue可以定義優先順序,宣告下一個彈出的元素是最需要的元素(優先順序最高)。當向PriorityQueue插入一個物件時,會在佇列中進行排序,預設的排序方法使用的是物件在佇列中的自然順序,但可以通過提供Comparator來修改這個順序。

2)Deque:介面表示的是一個雙向佇列(雙端佇列),可以在頭部和尾部任何一端新增和刪除元素,不支援在佇列中間插入元素。因此Deque的實現類即可以當成佇列使用,也可以當成棧使用。

迭代器

在java.lang包下面有一個介面Iterable,裡面包含方法iterator(),返回型別是Iterator介面型別,Collection介面繼承Iterable介面,Collection介面實現類實現了Iterator()方法,所以Collection集合體系可以使用迭代器或者foreach迴圈進行遍歷。

public interface Iterable<T> {
    Iterator<T> iterator();
}

Iterator介面如下

public interface Iterator<E> {
    //如果仍有元素可以迭代,返回true
    boolean hasNext();
    //返回迭代下一個元素
    E next();
    //刪除迭代器剛訪問過的元素
    default void remove(){}
    //jdk1.8新增的內容
    default void forEachRemaining(Consumer<? super E> action) {}
}

迭代器的工作就是為了遍歷並選擇序列中的物件,而不需要知道資料的底層結構。迭代器是輕量級物件,建立它的代價較小。

    1)Iterator迭代器只能單向移動,使用方法iterator()要求容器返回一個Iterator。Iterator將準備好返回第一個元素。

    2)使用next()獲取序列中的下一個元素。

    3)使用hasNext()檢查序列中是否還有元素。

    4)使用remove()將迭代器上次訪問的元素刪除。

ListIterator介面繼承自Iterator介面,在介面List中,ListIterator()方法返回的是ListIterator物件,專門用於遍歷List集合。

public interface ListIterator<E> extends Iterator<E> {
    //正向遍歷,存在元素,返回true
    boolean hasNext();
    //返回列表中下一個元素
    E next();
    void remove();
    //逆向遍歷,如果存在元素,返回true
    boolean hasPrevious();
    //返回列表中前一個元素
    E previous();
    //返回對next()呼叫所返回元素的索引
    int nextIndex();
    //返回對previous呼叫所返回的元素索引
    int previousIndex();
    //用指定元素替換next或者previous上次訪問的元素
    //如果在next或者previous上次呼叫之後列表結構被修改,將丟擲異常。
    void set(E e);
    //將指定的元素插入列表中
    void add(E e);
}

ListIterator介面定義的方法可以看出,

    1)可以實現雙向移動( 向前或者向後遍歷)

    2)產生相對迭代器在列表中指向的當前位置的前一個和後一個元素的索引。

    3)可以使用set()方法替換它訪問過的最後一個元素。

    4)可以使用add()方法在next()方法返回的元素之前或者previous()返回的元素之後插入一個元素。

    5)通過呼叫List集合中listIterator()方法產生一個指向List開始處的ListIterator,並且還可以通過listIterator(n)方法建立一個一開始就指向列表索引n的元素處的ListIterator。

關於迭代器需要注意:當執行緒A通過Collection集合中的方法iterator()方法獲取遍歷集合的迭代器時,如果此時集合的內容被其他執行緒修改,執行緒A將會丟擲ConcurrentModificationException異常