ArrayList源碼解析

這仨貨
  1. elementData:就是實際存儲元素的數(shù)組,被transient,表明不參與序列化喇辽,意味著elementData里的數(shù)據(jù)僅存在調(diào)用者的內(nèi)存中
  2. EMPTY_ELEMENT空數(shù)組
  3. DEFAULTCAPACITY_EMPTY_ELEMENT: 不同于EMPTY_ELEMENT岛琼,這個空的Object[]有啥用?
    (為什么要兩個空數(shù)組龙助?3號空數(shù)組用法如下,那么二號呢欺殿?其實二號要解決的是當(dāng)我想創(chuàng)建一個空集合時拔莱,即調(diào)用new ArrayList(0),在隨后調(diào)用add方法時,不會被自動擴容成大小為10匿又,這就是二者區(qū)別-defaultCapacity方灾。)


    無參構(gòu)造函數(shù)

    當(dāng)調(diào)用無參構(gòu)造函數(shù)時,將它賦給elementData碌更,這樣做感覺好像沒多大用裕偿?其實它就像一個標(biāo)記,什么時候會用到它呢针贬?當(dāng)?shù)谝粋€元素被添加的時候

add()

size: 是實際元素個數(shù)

擴容三姐妹之二三

---DEFAULT_CAPACITY = 10击费;也就是說當(dāng)你new ArrayList()調(diào)用add(E e)或是其它add方法后拢蛋,會根據(jù)需要創(chuàng)建一個Object[minCapacity]初始數(shù)組-------(感覺寫了半天細(xì)枝末節(jié)的東西)
---modeCount是用作Fail-Fast機制
---grow()執(zhí)行數(shù)組擴容操作桦他,利用Arrays.copyOf(),繼續(xù)追蹤發(fā)現(xiàn)是調(diào)用了System.arrayCopy(),創(chuàng)建了一個擴容后大小的新數(shù)組copy[],返回copy

ArrayList還有一類構(gòu)造函數(shù):ArrayList(Collection<? extends E> c),它什么原理呢谆棱? Collection接口有個toArray()快压,舉例如具體實現(xiàn)類ArrayList的toArray()里調(diào)用Arrays.copyOf(),如上所述它返還一個copy[]垃瞧,而該構(gòu)造函數(shù)里就利用了這個來將c轉(zhuǎn)化為數(shù)組賦給elementData蔫劣。其實很多地方都用到了Arrays.copy(),比如trimToSize()..

ADD():

ArrayList其實是一個動態(tài)變化的數(shù)組,我們來看它在添加刪除元素時的變化:
從add入手:add(E e); add(int index; E elementi); add(Collention<? extends E> c); add(int index, Collection<? extends E> c)四種方法个从。

  1. add(E e):首先會調(diào)用ensureCapacityInternal(size+1),該方法又會調(diào)用ensureEcplicitCapacity(),在該方法里如果size+1>elementData.length脉幢,則調(diào)用growth()方法進(jìn)行擴容歪沃,邏輯如下
擴容

一般情況下擴容為原來的1.5倍,這里又用到 了Arrays.copyOf()

  1. add(int index, E e)
add

顯而易見嫌松,先判斷index是否越界沪曙,在進(jìn)行擴容判斷,之后調(diào)用System.arraycopy()將原數(shù)組index及之后的元素后挪一位萎羔,最后添加

  1. add(Collention<? extends E> c)與add(int index, Collection<? extends E> c)核心類是toArray()與System.arraycopy(),與之前提的一樣(代碼不貼了--累人R鹤摺)

indexOf(Object o)與lastIndexOf(Object o)都會對o進(jìn)行null判斷,因為ArrayList可以添加null贾陷;clone()為淺拷貝缘眶,elementData數(shù)據(jù)不包括在內(nèi)

get,set,remove方法都沒什么好說的

removeAll(Collection<?> c), retainAll(Collection<?> c)

這兩個方法中若c==null則拋出NullPointException異常,接著調(diào)用batchRemove(Collection<?> c, boolean complement)

    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            //w == size則說明沒有改變髓废,返回false巷懈,removeAll與retainAll結(jié)果為false
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }

該方法在complement為true時,取elementData與c的交集慌洪,即相同部分保留砸喻;為false時,取elementData獨有部分保留蒋譬。所以removeAll調(diào)用batchRemove(c, false)割岛,retainAll調(diào)用batchRemove(c, true);

迭代器

  1. Iterator
    private class Itr implements Iterator<E> {
        int cursor;       // 下一個要返回的元素的下標(biāo)
        int lastRet = -1; // 被返回的元素的下標(biāo),即調(diào)用next()返回elementData[lastRet]
        int expectedModCount = modCount; //fail-fast,迭代中若數(shù)組被更改(add,remove
添加刪除操作)會造成二者不相等犯助,拋ConcurrentModificationException
        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();  //fail-fast
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData; 
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet); //調(diào)用的是ArrayList的remove方法
                cursor = lastRet; //lastRet表示被刪除的位置癣漆,后被cusor前挪一位填補上,cusor變?yōu)閘astRet
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
        //如果相對elementData中每個元素都執(zhí)行相同操作剂买,你可以寫一類實現(xiàn)Consumer接口惠爽,
復(fù)寫accept(),在調(diào)用該方法
        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

Consumer是個函數(shù)式接口瞬哼,函數(shù)描述符為:T → void, 多用于lambda

  1. ListIterator
   //繼承itr婚肆,實現(xiàn)ListIterator implements Iterator<E>,ListIterator拓展了Iterator
 private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            super();
            cursor = index;
        }
//是否有前一個元素
        public boolean hasPrevious() {
            return cursor != 0;
        }
//下一個元素位置
        public int nextIndex() {
            return cursor;
        }
//前一個元素位置
        public int previousIndex() {
            return cursor - 1;
        }
//返回前一個元素,即cusor-1處坐慰;cusor退一位较性,反復(fù)調(diào)用實現(xiàn)倒敘;如果之后你接著調(diào)用next(),
previous()將返回同一個結(jié)果
        @SuppressWarnings("unchecked")
        public E previous() {
            checkForComodification();
            int i = cursor - 1;
            if (i < 0)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i;
            return (E) elementData[lastRet = i];
        }
//下面的add()方法會重置lastRet = -1;所以add后避免調(diào)用set
        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
//add會插入到原本調(diào)用next函數(shù)返回的元素之前结胀,cusor自增1仍指向原本next函數(shù)返回的元素赞咙,
此時可通過previous來得到新增的元素;這樣設(shè)計保證了next函數(shù)不受影響
        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }

SubList extends AbstractList<E> implements RandomAccess

內(nèi)部類private class SubList糟港,作用就是生成一個[fromeIndex,toIndex)大小的小型List攀操,麻雀雖小五臟俱全,只能通過subList(int fromIndex, int toIndex)函數(shù)調(diào)用秸抚,功能實現(xiàn)依賴外部類ArrayList速和,實現(xiàn)了自己的迭代器ListIterator歹垫。

還有一方法Arraylist.sort在這篇文章里介紹MergeSort與TimSort,ComparableTimSort

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末颠放,一起剝皮案震驚了整個濱河市县钥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌慈迈,老刑警劉巖若贮,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異痒留,居然都是意外死亡谴麦,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進(jìn)店門伸头,熙熙樓的掌柜王于貴愁眉苦臉地迎上來匾效,“玉大人,你說我怎么就攤上這事恤磷∶婧撸” “怎么了?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵扫步,是天一觀的道長魔策。 經(jīng)常有香客問我,道長河胎,這世上最難降的妖魔是什么闯袒? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮游岳,結(jié)果婚禮上政敢,老公的妹妹穿的比我還像新娘。我一直安慰自己胚迫,他們只是感情好喷户,可當(dāng)我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著访锻,像睡著了一般褪尝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上朗若,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天恼五,我揣著相機與錄音昌罩,去河邊找鬼哭懈。 笑死,一個胖子當(dāng)著我的面吹牛茎用,可吹牛的內(nèi)容都是我干的遣总。 我是一名探鬼主播睬罗,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼旭斥!你這毒婦竟也來了容达?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤垂券,失蹤者是張志新(化名)和其女友劉穎花盐,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體菇爪,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡算芯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了凳宙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片熙揍。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖氏涩,靈堂內(nèi)的尸體忽然破棺而出届囚,到底是詐尸還是另有隱情,我是刑警寧澤是尖,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布意系,位于F島的核電站,受9級特大地震影響饺汹,放射性物質(zhì)發(fā)生泄漏昔字。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一首繁、第九天 我趴在偏房一處隱蔽的房頂上張望作郭。 院中可真熱鬧,春花似錦弦疮、人聲如沸夹攒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咏尝。三九已至,卻和暖如春啸罢,著一層夾襖步出監(jiān)牢的瞬間编检,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工扰才, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留允懂,地道東北人。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓衩匣,卻偏偏與公主長得像蕾总,于是被迫代替她去往敵國和親粥航。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,562評論 2 349

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