Java集合源碼分析之超級接口:Collection_一點課堂(多岸學院)

Collection

CollectionListQueueSet的超集,它直接繼承於Iterable,也就是全部的Collection集合類都支持for-each循環。除此以外,Collection也是面向接口編程的典範,經過它能夠在多種實現類間轉換,這也是面向對象編程的魅力之一。java

方法定義

在閱讀源碼前,咱們能夠先自行想象一下,若是咱們想封裝下數組或鏈表以方便操做,咱們須要封裝哪些功能呢?好比:統計大小、插入或刪除數據、清空、是否包含某條數據,等等。而Collection就是對這些經常使用操做進行提取,只是其很全面、很通用。下面咱們看看它都提供了哪些方法。編程

//返回集合的長度,若是長度大於Integer.MAX_VALUE,返回Integer.MAX_VALUE
int size();

//若是集合元素總數爲0,返回true
boolean isEmpty();

//判斷集合中是否包含指定的元素,其依據是equals()方法
boolean contains(Object o);

//返回一個包含集合中全部元素的數組
Object[] toArray();

//與上個相似,只是增長了類型的轉換
<T> T[] toArray(T[] a);

//向集合中加入一個元素,若是成功加入則返回true,若是加入失敗,或者因集合自己已經包含同個元素而再也不加入時,返回false
boolean add(E e);

//從集合中刪除指定元素的單個實例
boolean remove(Object o);

//若是集合包含指定集合中的全部元素,返回true
boolean containsAll(Collection<?> c);

//把指定集合中的全部元素添加到集合中,但在此期間,若是指定的集合發生了改變,可能出現意想不到的事情
boolean addAll(Collection<? extends E> c);

//從集合中刪除全部包含在指定集合中的元素
boolean removeAll(Collection<?> c);

//僅保留集合中包含在指定集合中的元素
boolean retainAll(Collection<?> c);

//清空集合
void clear();

//將此方法抽象,是保證全部子類都覆寫此方法,以保證equals的正確行爲
boolean equals(Object o);

//同上
int hashCode();

//這個方法在JDK1.8中提供了默認的實現,會使用Iterator的形式刪除符合條件的元素
default boolean removeIf(Predicate<? super E> filter){
    Objects.requireNonNull(filter);
    boolean removed = false;
    final Iterator<E> each = iterator();
    while (each.hasNext()) {
        if (filter.test(each.next())) {
            each.remove();
            removed = true;
        }
    }
    return removed;
}

超級實現類:AbstractCollection

Collection中定義的許多方法,根據現有的定義以及繼承的Iterable,均可以在抽象類中實現,這樣能夠減小實現類須要實現的方法,這個抽象類就是AbstractCollection數組

首先咱們關注下其文檔,裏面有兩句說明可能會影響咱們的繼承:app

To implement an unmodifiable collection, the programmer needs only to extend this class and provide implementations for the iterator and size methods. (The iterator returned by the iterator method must implement hasNext and next.)ide

To implement a modifiable collection, the programmer must additionally override this class's add method (which otherwise throws an UnsupportedOperationException), and the iterator returned by the iterator method must additionally implement its remove method.學習

大致意思是說,若是要實現一個不可修改的集合,只須要重寫iteratorsize接口就能夠,而且返回的Iterator須要實現hasNextnext。而要實現一個能夠修改的集合,還必須重寫add方法(默認會拋出異常),返回的Iterator還須要實現remove方法。ui

方法定義

//這個毫無疑問,是能夠直接獲取的
public boolean isEmpty() {
    return size() == 0;
}

//這個方法由於Iterator的存在,能夠進行一致性封裝,這裏須要注意的是對象的比較是經過equals方法,由於調用到了it.next()與it.hasNext(),這也是爲何文檔註釋會寫實現集合類須要重寫Iterator的這兩個方法。
public boolean contains(Object o) {
    Iterator<E> it = iterator();
    if (o==null) {
        while (it.hasNext())
            if (it.next()==null)
                return true;
    } else {
        while (it.hasNext())
            if (o.equals(it.next()))
                return true;
    }
    return false;
}

//和contains相似,也是經過Iterator實現的,但其會調用it.remove()方法,這也是爲何文檔註釋會寫實現能夠修改的集合類時須要重寫Iterator的remove方法。
public boolean remove(Object o) {
    //...省略,這裏調用了it.remove()方法
}

相似的方法還有containsAll(Collection<?> c)addAll(Collection<? extends E> c)removeAll(Collection<?> c)retainAll(Collection<?> c)clear()等,都須要利用到Iterator的特性,這裏就再也不一一贅述了。this

另外還有一個toArray()的方法實現略微不一樣,能夠看看其具體實現。3d

//這個實現相對複雜一些,能夠看到擴容最主要的手段是Arrays.copyOf()方法,
//也就是須要將原數組經過複製到新的數組中來實現的。
//注意這裏返回的順序和Iterator順序一致
//在這裏實現是爲了方便不一樣具體實現類互相轉換,咱們在後續會屢次見到此方法
public Object[] toArray() {
    //先根據當前集合大小聲明一個數組
    Object[] r = new Object[size()];
    Iterator<E> it = iterator();
    for (int i = 0; i < r.length; i++) {
        //集合元素沒那麼多,說明不須要那麼大的數組
        if (! it.hasNext()) 
            return Arrays.copyOf(r, i); //僅返回賦完值的部分
        r[i] = it.next();
    }
    //元素比從size()中獲取的更多,就須要進一步調整數組大小
    return it.hasNext() ? finishToArray(r, it) : r;
}

private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
    //記錄當前大小
    int i = r.length;
    while (it.hasNext()) {
        int cap = r.length;
        //r的長度不夠,繼續分配
        if (i == cap) {
            //擴充方式爲cap+cap/2+1,也就是1.5倍擴容
            int newCap = cap + (cap >> 1) + 1;
            // 超過了最大容量,MAX_ARRAY_SIZE=Integer.MAX_VALUE-8
            if (newCap - MAX_ARRAY_SIZE > 0)
                //從新設置cap的值
                newCap = hugeCapacity(cap + 1);
            
            //對r進行擴容
            r = Arrays.copyOf(r, newCap);
        }
        //賦值,進入下一輪循環
        r[i++] = (T)it.next();
    }
    // 因爲以前擴容是1.5倍進行的,最後再將其設置到和r實際須要的相同
    return (i == r.length) ? r : Arrays.copyOf(r, i);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // 超過了最大正整數,也就是負數
        throw new OutOfMemoryError
            ("Required array size too large");
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

//和toArray()方法相似,就再也不贅述,具體能夠查看源碼
public <T> T[] toArray(T[] a) {
    //...
}

除了以上這些方法,AbstractCollection還實現了toString方法,其是經過StringBuilder拼接了每一個元素的toString完成的,也並不複雜。這裏能夠看下其源碼:code

public String toString() {
    Iterator<E> it = iterator();
    if (! it.hasNext())
        return "[]";

    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) {
        E e = it.next();
        sb.append(e == this ? "(this Collection)" : e);
        if (! it.hasNext())
            return sb.append(']').toString();
        sb.append(',').append(' ');
    }
}

【感謝您能看完,若是可以幫到您,麻煩點個贊~】

更多經驗技術歡迎前來共同窗習交流: 一點課堂-爲夢想而奮鬥的在線學習平臺 http://www.yidiankt.com/

![關注公衆號,回覆「1」免費領取-【java核心知識點】] file

QQ討論羣:616683098

QQ:3184402434

想要深刻學習的同窗們能夠加我QQ一塊兒學習討論~還有全套資源分享,經驗探討,等你哦! 在這裏插入圖片描述

相關文章
相關標籤/搜索