Android ArrayList源碼分析

/**

* ArrayList is an implementation of {@linkList}, backed by an array.

* All optional operations including adding, removing, and replacing elements are supported.

*

*

All elements are permitted, including null.

*

*

This class is a good choice as your default {@codeList} implementation.

* {@linkVector} synchronizes all operations, but not necessarily in a way that's

* meaningful to your application: synchronizing each call to {@codeget}, for example, is not

* equivalent to synchronizing the list and iterating over it (which is probably what you intended).

* {@linkjava.util.concurrent.CopyOnWriteArrayList} is intended for the special case of very high

* concurrency, frequent traversals, and very rare mutations.

*

*@paramThe element type of this list.

*@since1.2

*/

以上是ArrayList的類前注釋愉耙。大致意思如下:
ArrayList是底層用數(shù)組實(shí)現(xiàn)的List贮尉。支持增刪改等操作。支持包括null的任意類型元素朴沿。Vector使用synchronized來進(jìn)行線程同步猜谚;CopyOnWriteArrayList適合確保高并發(fā)場景下的線程安全败砂;在一般情況下使用ArrayList效率較高。

下面從代碼里的幾個(gè)主要屬性和方法入手魏铅。

    /**
     * The minimum amount by which the capacity of an ArrayList will increase.
     * This tuning parameter controls a time-space tradeoff. This value (12)
     * gives empirically good results and is arguably consistent with the
     * RI's specified default initial capacity of 10: instead of 10, we start
     * with 0 (sans allocation) and jump to 12.
     */
    private static final int MIN_CAPACITY_INCREMENT = 12;

與JDK源碼不同昌犹,JDK初始容量是10,而Android下是初始0再跳到12览芳。不不不你說12好一般人也看不出妙在哪啊難道是8派和16派僵持不下最后折中成12嗎斜姥。

    /**
     * The elements in this list, followed by nulls.
     */
    transient Object[] array;

Object數(shù)組array用來存儲元素。值得注意的是修飾符transient沧竟。transient的作用是使可序列化對象中的指定屬性不被序列化铸敏。而在這里使用transient的目的,是因?yàn)橹苯有蛄谢痑rray的話array里可能存在一定數(shù)量的空值導(dǎo)致浪費(fèi)資源悟泵。

     /**
     * Adds the specified object at the end of this {@code ArrayList}.
     *
     * @param object
     *            the object to add.
     * @return always true
     */
    @Override public boolean add(E object) {
        Object[] a = array;
        int s = size;
        if (s == a.length) {
            Object[] newArray = new Object[s +
                    (s < (MIN_CAPACITY_INCREMENT / 2) ?
                     MIN_CAPACITY_INCREMENT : s >> 1)];
            System.arraycopy(a, 0, newArray, 0, s);
            array = a = newArray;
        }
        a[s] = object;
        size = s + 1;
        modCount++;
        return true;
    }

    /**
     * Inserts the specified object into this {@code ArrayList} at the specified
     * location. The object is inserted before any previous element at the
     * specified location. If the location is equal to the size of this
     * {@code ArrayList}, the object is added at the end.
     *
     * @param index
     *            the index at which to insert the object.
     * @param object
     *            the object to add.
     * @throws IndexOutOfBoundsException
     *             when {@code location < 0 || location > size()}
     */
    @Override public void add(int index, E object) {
        Object[] a = array;
        int s = size;
        if (index > s || index < 0) {
            throwIndexOutOfBoundsException(index, s);
        }

        if (s < a.length) {
            System.arraycopy(a, index, a, index + 1, s - index);
        } else {
            // assert s == a.length;
            Object[] newArray = new Object[newCapacity(s)];
            System.arraycopy(a, 0, newArray, 0, index);
            System.arraycopy(a, index, newArray, index + 1, s - index);
            array = a = newArray;
        }
        a[index] = object;
        size = s + 1;
        modCount++;
    }

    /**
     * This method controls the growth of ArrayList capacities.  It represents
     * a time-space tradeoff: we don't want to grow lists too frequently
     * (which wastes time and fragments storage), but we don't want to waste
     * too much space in unused excess capacity.
     *
     * NOTE: This method is inlined into {@link #add(Object)} for performance.
     * If you change the method, change it there too!
     */
    private static int newCapacity(int currentCapacity) {
        int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ?
                MIN_CAPACITY_INCREMENT : currentCapacity >> 1);
        return currentCapacity + increment;
    }

增搞坝。如果數(shù)組已滿則進(jìn)行擴(kuò)容。擴(kuò)容方式為:若容量小于6則增加12魁袜,否則1.5倍擴(kuò)容桩撮。

    /**
     * Adds the objects in the specified collection to this {@code ArrayList}.
     *
     * @param collection
     *            the collection of objects.
     * @return {@code true} if this {@code ArrayList} is modified, {@code false}
     *         otherwise.
     */
    @Override public boolean addAll(Collection<? extends E> collection) {
        Object[] newPart = collection.toArray();
        int newPartSize = newPart.length;
        if (newPartSize == 0) {
            return false;
        }
        Object[] a = array;
        int s = size;
        int newSize = s + newPartSize; // If add overflows, arraycopy will fail
        if (newSize > a.length) {
            int newCapacity = newCapacity(newSize - 1);  // ~33% growth room
            Object[] newArray = new Object[newCapacity];
            System.arraycopy(a, 0, newArray, 0, s);
            array = a = newArray;
        }
        System.arraycopy(newPart, 0, a, s, newPartSize);
        size = newSize;
        modCount++;
        return true;
    }

批量增。又與JDK實(shí)現(xiàn)不同:JDK是擴(kuò)容為新容量與1.5倍容量的較大者峰弹;此處為 以新容量為基準(zhǔn)1.5倍擴(kuò)容店量。如newCapacity方法的注釋所寫:這是時(shí)間空間權(quán)衡,既不想頻繁擴(kuò)容(數(shù)組復(fù)制)鞠呈,又不想浪費(fèi)過多冗余空間融师。就這種擴(kuò)容方式而言,容量比JDK的方式要大蚁吝,減少了擴(kuò)容次數(shù)旱爆,想必思路傾向于以空間換時(shí)間。

    @SuppressWarnings("unchecked") @Override public E get(int index) {
        if (index >= size) {
            throwIndexOutOfBoundsException(index, size);
        }
        return (E) array[index];
    }

查窘茁。直接返回array里對應(yīng)位置的對象怀伦。

    /**
     * Searches this {@code ArrayList} for the specified object.
     *
     * @param object
     *            the object to search for.
     * @return {@code true} if {@code object} is an element of this
     *         {@code ArrayList}, {@code false} otherwise
     */
    @Override public boolean contains(Object object) {
        Object[] a = array;
        int s = size;
        if (object != null) {
            for (int i = 0; i < s; i++) {
                if (object.equals(a[i])) {
                    return true;
                }
            }
        } else {
            for (int i = 0; i < s; i++) {
                if (a[i] == null) {
                    return true;
                }
            }
        }
        return false;
    }

檢查是否包含。遍歷array找出與目標(biāo)相同的對象山林。indexOf方法和lastIndexOf方法也是相同的實(shí)現(xiàn)思路房待。

    /**
     * Removes the object at the specified location from this list.
     *
     * @param index
     *            the index of the object to remove.
     * @return the removed object.
     * @throws IndexOutOfBoundsException
     *             when {@code location < 0 || location >= size()}
     */
    @Override public E remove(int index) {
        Object[] a = array;
        int s = size;
        if (index >= s) {
            throwIndexOutOfBoundsException(index, s);
        }
        @SuppressWarnings("unchecked") E result = (E) a[index];
        System.arraycopy(a, index + 1, a, index, --s - index);
        a[s] = null;  // Prevent memory leak
        size = s;
        modCount++;
        return result;
    }

刪。將array對應(yīng)位置的對象找出以便返回驼抹,再通過數(shù)組復(fù)制將該位置后的對象前移一位桑孩,最后為了防止內(nèi)存泄漏將原來的末位置空。

    /**
     * Replaces the element at the specified location in this {@code ArrayList}
     * with the specified object.
     *
     * @param index
     *            the index at which to put the specified object.
     * @param object
     *            the object to add.
     * @return the previous element at the index.
     * @throws IndexOutOfBoundsException
     *             when {@code location < 0 || location >= size()}
     */
    @Override public E set(int index, E object) {
        Object[] a = array;
        if (index >= size) {
            throwIndexOutOfBoundsException(index, size);
        }
        @SuppressWarnings("unchecked") E result = (E) a[index];
        a[index] = object;
        return result;
    }

改框冀。直接將array里對應(yīng)位置的對象指向新對象流椒。

    private void writeObject(ObjectOutputStream stream) throws IOException {
        stream.defaultWriteObject();
        stream.writeInt(array.length);
        for (int i = 0; i < size; i++) {
            stream.writeObject(array[i]);
        }
    }

    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
        stream.defaultReadObject();
        int cap = stream.readInt();
        if (cap < size) {
            throw new InvalidObjectException(
                    "Capacity: " + cap + " < size: " + size);
        }
        array = (cap == 0 ? EmptyArray.OBJECT : new Object[cap]);
        for (int i = 0; i < size; i++) {
            array[i] = stream.readObject();
        }
    }

writeObject和readObject這兩個(gè)方法是序列化和反序列化需要特殊處理的類必須實(shí)現(xiàn)的方法,因?yàn)樯衔乃f的transient修飾符的關(guān)系A(chǔ)rrayList并非直接序列化array明也。ArrayList序列化時(shí)只序列化實(shí)際存儲大小的部分而不是整個(gè)array宣虾,從而提高了序列化效率极谊。

總而言之,ArrayList是基于數(shù)組實(shí)現(xiàn)的列表結(jié)構(gòu)安岂,查找指定位置快,相對的增刪慢帆吻。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末域那,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子猜煮,更是在濱河造成了極大的恐慌次员,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件王带,死亡現(xiàn)場離奇詭異淑蔚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)愕撰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進(jìn)店門刹衫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人搞挣,你說我怎么就攤上這事带迟。” “怎么了囱桨?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵仓犬,是天一觀的道長。 經(jīng)常有香客問我舍肠,道長搀继,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任翠语,我火速辦了婚禮叽躯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘肌括。我一直安慰自己险毁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布们童。 她就那樣靜靜地躺著畔况,像睡著了一般。 火紅的嫁衣襯著肌膚如雪慧库。 梳的紋絲不亂的頭發(fā)上跷跪,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天,我揣著相機(jī)與錄音齐板,去河邊找鬼吵瞻。 笑死葛菇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的橡羞。 我是一名探鬼主播眯停,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼卿泽!你這毒婦竟也來了莺债?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤签夭,失蹤者是張志新(化名)和其女友劉穎齐邦,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體第租,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡措拇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了慎宾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丐吓。...
    茶點(diǎn)故事閱讀 38,673評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖趟据,靈堂內(nèi)的尸體忽然破棺而出汰蜘,到底是詐尸還是另有隱情,我是刑警寧澤之宿,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布族操,位于F島的核電站,受9級特大地震影響比被,放射性物質(zhì)發(fā)生泄漏色难。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一等缀、第九天 我趴在偏房一處隱蔽的房頂上張望枷莉。 院中可真熱鬧,春花似錦尺迂、人聲如沸笤妙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蹲盘。三九已至,卻和暖如春膳音,著一層夾襖步出監(jiān)牢的瞬間召衔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工祭陷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留苍凛,地道東北人趣席。 一個(gè)月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像醇蝴,于是被迫代替她去往敵國和親宣肚。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評論 2 349

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