Java集合源碼分析之超級(jí)接口:Collection

Collection

CollectionList棵逊、QueueSet的超集伤疙,它直接繼承于Iterable,也就是所有的Collection集合類都支持for-each循環(huán)辆影。除此之外徒像,Collection也是面向接口編程的典范,通過(guò)它可以在多種實(shí)現(xiàn)類間轉(zhuǎn)換蛙讥,這也是面向?qū)ο缶幊痰镊攘χ弧?/p>

方法定義

在閱讀源碼前锯蛀,我們可以先自行想象一下,如果我們想封裝下數(shù)組或鏈表以方便操作键菱,我們需要封裝哪些功能呢谬墙?比如:統(tǒng)計(jì)大小今布、插入或刪除數(shù)據(jù)经备、清空拭抬、是否包含某條數(shù)據(jù),等等侵蒙。而Collection就是對(duì)這些常用操作進(jìn)行提取造虎,只是其很全面、很通用纷闺。下面我們看看它都提供了哪些方法。

//返回集合的長(zhǎng)度,如果長(zhǎng)度大于Integer.MAX_VALUE六剥,返回Integer.MAX_VALUE
int size();

//如果集合元素總數(shù)為0尸执,返回true
boolean isEmpty();

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

//返回一個(gè)包含集合中所有元素的數(shù)組
Object[] toArray();

//與上個(gè)類似浸卦,只是增加了類型的轉(zhuǎn)換
<T> T[] toArray(T[] a);

//向集合中加入一個(gè)元素署鸡,如果成功加入則返回true,如果加入失敗限嫌,或者因集合本身已經(jīng)包含同個(gè)元素而不再加入時(shí)靴庆,返回false
boolean add(E e);

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

//如果集合包含指定集合中的所有元素,返回true
boolean containsAll(Collection<?> c);

//把指定集合中的所有元素添加到集合中怒医,但在此期間炉抒,如果指定的集合發(fā)生了改變,可能出現(xiàn)意想不到的事情
boolean addAll(Collection<? extends E> c);

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

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

//清空集合
void clear();

//將此方法抽象稚叹,是保證所有子類都覆寫此方法焰薄,以保證equals的正確行為
boolean equals(Object o);

//同上
int hashCode();

//這個(gè)方法在JDK1.8中提供了默認(rèn)的實(shí)現(xiàn),會(huì)使用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;
}

超級(jí)實(shí)現(xiàn)類:AbstractCollection

Collection中定義的許多方法扒袖,根據(jù)現(xiàn)有的定義以及繼承的Iterable蛤奥,都可以在抽象類中實(shí)現(xiàn),這樣可以減少實(shí)現(xiàn)類需要實(shí)現(xiàn)的方法僚稿,這個(gè)抽象類就是AbstractCollection凡桥。

首先我們關(guān)注下其文檔,里面有兩句說(shuō)明可能會(huì)影響我們的繼承:

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.)

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.

大體意思是說(shuō)蚀同,如果要實(shí)現(xiàn)一個(gè)不可修改的集合缅刽,只需要重寫iteratorsize接口就可以,并且返回的Iterator需要實(shí)現(xiàn)hasNextnext蠢络。而要實(shí)現(xiàn)一個(gè)可以修改的集合衰猛,還必須重寫add方法(默認(rèn)會(huì)拋出異常),返回的Iterator還需要實(shí)現(xiàn)remove方法刹孔。

方法定義

//這個(gè)毫無(wú)疑問(wèn)啡省,是可以直接獲取的
public boolean isEmpty() {
    return size() == 0;
}

//這個(gè)方法因?yàn)镮terator的存在,可以進(jìn)行一致性封裝,這里需要注意的是對(duì)象的比較是通過(guò)equals方法卦睹,因?yàn)檎{(diào)用到了it.next()與it.hasNext()畦戒,這也是為什么文檔注釋會(huì)寫實(shí)現(xiàn)集合類需要重寫Iterator的這兩個(gè)方法。
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類似结序,也是通過(guò)Iterator實(shí)現(xiàn)的障斋,但其會(huì)調(diào)用it.remove()方法,這也是為什么文檔注釋會(huì)寫實(shí)現(xiàn)可以修改的集合類時(shí)需要重寫Iterator的remove方法徐鹤。
public boolean remove(Object o) {
    //...省略垃环,這里調(diào)用了it.remove()方法
}

類似的方法還有containsAll(Collection<?> c)addAll(Collection<? extends E> c)返敬、removeAll(Collection<?> c)遂庄、retainAll(Collection<?> c)clear()等,都需要利用到Iterator的特性劲赠,這里就不再一一贅述了涛目。

另外還有一個(gè)toArray()的方法實(shí)現(xiàn)略微不同,可以看看其具體實(shí)現(xiàn)经磅。

//這個(gè)實(shí)現(xiàn)相對(duì)復(fù)雜一些泌绣,可以看到擴(kuò)容最主要的手段是Arrays.copyOf()方法,
//也就是需要將原數(shù)組通過(guò)復(fù)制到新的數(shù)組中來(lái)實(shí)現(xiàn)的预厌。
//注意這里返回的順序和Iterator順序一致
//在這里實(shí)現(xiàn)是為了方便不同具體實(shí)現(xiàn)類互相轉(zhuǎn)換阿迈,我們?cè)诤罄m(xù)會(huì)多次見到此方法
public Object[] toArray() {
    //先根據(jù)當(dāng)前集合大小聲明一個(gè)數(shù)組
    Object[] r = new Object[size()];
    Iterator<E> it = iterator();
    for (int i = 0; i < r.length; i++) {
        //集合元素沒(méi)那么多,說(shuō)明不需要那么大的數(shù)組
        if (! it.hasNext()) 
            return Arrays.copyOf(r, i); //僅返回賦完值的部分
        r[i] = it.next();
    }
    //元素比從size()中獲取的更多轧叽,就需要進(jìn)一步調(diào)整數(shù)組大小
    return it.hasNext() ? finishToArray(r, it) : r;
}

private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
    //記錄當(dāng)前大小
    int i = r.length;
    while (it.hasNext()) {
        int cap = r.length;
        //r的長(zhǎng)度不夠苗沧,繼續(xù)分配
        if (i == cap) {
            //擴(kuò)充方式為cap+cap/2+1,也就是1.5倍擴(kuò)容
            int newCap = cap + (cap >> 1) + 1;
            // 超過(guò)了最大容量炭晒,MAX_ARRAY_SIZE=Integer.MAX_VALUE-8
            if (newCap - MAX_ARRAY_SIZE > 0)
                //重新設(shè)置cap的值
                newCap = hugeCapacity(cap + 1);
            
            //對(duì)r進(jìn)行擴(kuò)容
            r = Arrays.copyOf(r, newCap);
        }
        //賦值待逞,進(jìn)入下一輪循環(huán)
        r[i++] = (T)it.next();
    }
    // 由于之前擴(kuò)容是1.5倍進(jìn)行的,最后再將其設(shè)置到和r實(shí)際需要的相同
    return (i == r.length) ? r : Arrays.copyOf(r, i);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // 超過(guò)了最大正整數(shù)网严,也就是負(fù)數(shù)
        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還實(shí)現(xiàn)了toString方法怜庸,其是通過(guò)StringBuilder拼接了每個(gè)元素的toString完成的,也并不復(fù)雜垢村。這里可以看下其源碼:

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(' ');
    }
}

上一篇:Java集合源碼分析之Iterable概述

下一篇:Java集合源碼分析之List(一):超級(jí)接口List


我是飛機(jī)醬割疾,如果您喜歡我的文章,可以關(guān)注我~

編程之路嘉栓,道阻且長(zhǎng)宏榕。唯拓诸,路漫漫其修遠(yuǎn)兮,吾將上下而求索麻昼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末奠支,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子涌献,更是在濱河造成了極大的恐慌胚宦,老刑警劉巖首有,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件燕垃,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡井联,警方通過(guò)查閱死者的電腦和手機(jī)卜壕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)烙常,“玉大人轴捎,你說(shuō)我怎么就攤上這事〔显啵” “怎么了侦副?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)驼鞭。 經(jīng)常有香客問(wèn)我秦驯,道長(zhǎng),這世上最難降的妖魔是什么挣棕? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任译隘,我火速辦了婚禮,結(jié)果婚禮上洛心,老公的妹妹穿的比我還像新娘固耘。我一直安慰自己,他們只是感情好词身,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布厅目。 她就那樣靜靜地躺著,像睡著了一般法严。 火紅的嫁衣襯著肌膚如雪损敷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天渐夸,我揣著相機(jī)與錄音嗤锉,去河邊找鬼。 笑死墓塌,一個(gè)胖子當(dāng)著我的面吹牛瘟忱,可吹牛的內(nèi)容都是我干的奥额。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼访诱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼垫挨!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起触菜,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤九榔,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后涡相,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哲泊,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年催蝗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了切威。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡丙号,死狀恐怖先朦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情犬缨,我是刑警寧澤喳魏,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站怀薛,受9級(jí)特大地震影響刺彩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜乾戏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一迂苛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鼓择,春花似錦三幻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至摆出,卻和暖如春朗徊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背偎漫。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工爷恳, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人象踊。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓温亲,卻偏偏與公主長(zhǎng)得像棚壁,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子栈虚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Scala的集合類可以從三個(gè)維度進(jìn)行切分: 可變與不可變集合(Immutable and mutable coll...
    時(shí)待吾閱讀 5,823評(píng)論 0 4
  • 對(duì)象的創(chuàng)建與銷毀 Item 1: 使用static工廠方法袖外,而不是構(gòu)造函數(shù)創(chuàng)建對(duì)象:僅僅是創(chuàng)建對(duì)象的方法,并非Fa...
    孫小磊閱讀 1,983評(píng)論 0 3
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法魂务,類相關(guān)的語(yǔ)法曼验,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法粘姜,異常的語(yǔ)法鬓照,線程的語(yǔ)...
    子非魚_t_閱讀 31,639評(píng)論 18 399
  • Java源碼研究之容器(1) 如何看源碼 很多時(shí)候我們看源碼, 看完了以后經(jīng)常也沒(méi)啥收獲, 有些地方看得懂, 有些...
    駱駝騎士閱讀 995評(píng)論 0 22
  • It's amazing for me to find that metaphors in English. It...
    友人醬_zZ閱讀 540評(píng)論 1 4