ArrayList

一、概述

ArrayList底層數(shù)據(jù)結(jié)構(gòu)為數(shù)組扔字,故保持了數(shù)組的基本特點(diǎn):隨機(jī)訪問(wèn)速度較快育拨,刪除和插入(如果是末尾速度也還好)數(shù)據(jù)速度較慢,因?yàn)橐肧ystem.arraycopy()來(lái)移動(dòng)这橙。默認(rèn)初始容量為10奏窑,超出容量擴(kuò)容按50%增加。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
     * DEFAULT_CAPACITY when the first element is added.
     */
    private transient Object[] elementData;

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;
    .........

其中elementData(真正保存數(shù)據(jù)的數(shù)組)屈扎,注意到是transient修飾的埃唯,為什么呢?首先鹰晨,序列化是對(duì)象轉(zhuǎn)為字節(jié)序列的過(guò)程墨叛,反序列化則是字節(jié)序列回復(fù)為對(duì)象的過(guò)程止毕。transient是用來(lái)表示一個(gè)域不是該對(duì)象序行化的一部分,當(dāng)一個(gè)對(duì)象被序行化的時(shí)候漠趁,transient修飾的變量的值是不包括在序行化中的扁凛。elementData用transient修飾的原因在于elementData里面不是所有的元素都有數(shù)據(jù),因?yàn)槿萘康膯?wèn)題棚潦,elementData里面有一些元素是空的令漂,這種是沒(méi)有必要序列化的。那ArrayList是可以進(jìn)行序列化的丸边,那elementData是怎么進(jìn)行序列化的叠必?ArrayList是通過(guò)其中的兩個(gè)方式實(shí)現(xiàn)的:readObject和writeObject。

    /**
     * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
     * deserialize it).
     */
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in capacity
        s.readInt(); // ignored

        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // Read in all elements in the proper order.
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }

    /**
     * Save the state of the <tt>ArrayList</tt> instance to a stream (that
     * is, serialize it).
     *
     * @serialData The length of the array backing the <tt>ArrayList</tt>
     *             instance is emitted (int), followed by all of its elements
     *             (each an <tt>Object</tt>) in the proper order.
     */
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

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

二妹窖、主要實(shí)現(xiàn)

1纬朝、構(gòu)造函數(shù)

ArrayList(int initialCapacity) :構(gòu)造具有初始容量的空列表;
ArrayList():默認(rèn)構(gòu)造函數(shù)骄呼,提供初始容量為10的空列表共苛;
ArrayList(Collection<? extends E> c):構(gòu)造一個(gè)包含指定collection 的元素的列表,這些元素是按照該 collection 的迭代器返回它們的順序排列的蜓萄。

/**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
    }

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        super();
        this.elementData = EMPTY_ELEMENTDATA;
    }

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    }
2隅茎、trimToSize

是為了縮小elementData的大小以達(dá)到節(jié)約內(nèi)存的目的,比如某次場(chǎng)景需要擴(kuò)容至100嫉沽,而此后size存儲(chǔ)量基本在10以內(nèi)辟犀,那么就可以用這個(gè)函數(shù)了。另外绸硕,在ArrayList中常用到Arrays.copyof堂竟,其底層實(shí)現(xiàn)是通過(guò)System.arraycopy來(lái)完成的。

public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = Arrays.copyOf(elementData, size);
        }
    }
3玻佩、新增元素

add(E e)出嘹、add(int index, E element)、addAll(Collection<? extends E> c)咬崔、addAll(int index, Collection<? extends E> c)税稼、set(int index, E element) ,這里主要分析add:

/**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

上述代碼中重點(diǎn)關(guān)注grow方法垮斯,新增元素如果需要擴(kuò)容郎仆,則增加50%。另外在add和remove中都存在modcount甚脉,修改次數(shù),在readObject铆农、writeObject牺氨、Itr中的next中都有用到狡耻,在這些方法中如果modcount改變了將會(huì)拋出異常:ConcurrentModificationException()。意思就是在遍歷遍歷的過(guò)程中如果對(duì)數(shù)組進(jìn)行了增刪操作將會(huì)拋出異常猴凹。以Itr舉例夷狰,因?yàn)锳rrayList被設(shè)計(jì)成非同步的,所以如果在遍歷集合過(guò)程中刪除元素不拋出異常郊霎,則會(huì)拋出:ArrayIndexOutOfBoundsException沼头。

private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            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);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

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

remove(int index)书劝、remove(Object o)进倍、removeRange(int fromIndex, int toIndex)、removeAll()购对。

/**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * @param index the index of the element to be removed
     * @return the element that was removed from the list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

查找很簡(jiǎn)單猾昆,就不分析了。

三骡苞、區(qū)別與聯(lián)系

1垂蜗、與LinkedList

1)、ArrayList是實(shí)現(xiàn)了基于動(dòng)態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu)解幽,LinkedList基于鏈表的數(shù)據(jù)結(jié)構(gòu)贴见。
2)、對(duì)于隨機(jī)訪問(wèn)get和set躲株,ArrayList覺(jué)得優(yōu)于LinkedList片部,因?yàn)長(zhǎng)inkedList要移動(dòng)指針。
3)徘溢、對(duì)于新增和刪除操作add和remove(不是在尾部添加刪除)吞琐,LinkedList比較占優(yōu)勢(shì),因?yàn)锳rrayList要移動(dòng)數(shù)據(jù)然爆。

2站粟、與vector

1)、Vector和ArrayList幾乎是完全相同的,唯一的區(qū)別在于Vector是同步類(synchronized)曾雕,屬于強(qiáng)同步類奴烙。因此開(kāi)銷就比ArrayList要大,訪問(wèn)要慢剖张。正常情況下,大多數(shù)的Java程序員使用ArrayList而不是Vector,因?yàn)橥酵耆梢杂沙绦騿T自己來(lái)控制切诀。
2)、Vector每次擴(kuò)容請(qǐng)求其大小的2倍空間搔弄,而ArrayList是1.5倍幅虑。
3)、Vector還有一個(gè)子類Stack.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末顾犹,一起剝皮案震驚了整個(gè)濱河市倒庵,隨后出現(xiàn)的幾起案子褒墨,更是在濱河造成了極大的恐慌,老刑警劉巖擎宝,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件郁妈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡绍申,警方通過(guò)查閱死者的電腦和手機(jī)噩咪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)极阅,“玉大人胃碾,你說(shuō)我怎么就攤上這事⊥科ǎ” “怎么了书在?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)拆又。 經(jīng)常有香客問(wèn)我儒旬,道長(zhǎng),這世上最難降的妖魔是什么帖族? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任栈源,我火速辦了婚禮,結(jié)果婚禮上竖般,老公的妹妹穿的比我還像新娘甚垦。我一直安慰自己,他們只是感情好涣雕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布艰亮。 她就那樣靜靜地躺著,像睡著了一般挣郭。 火紅的嫁衣襯著肌膚如雪迄埃。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天兑障,我揣著相機(jī)與錄音侄非,去河邊找鬼。 笑死流译,一個(gè)胖子當(dāng)著我的面吹牛逞怨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播福澡,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼叠赦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了革砸?” 一聲冷哼從身側(cè)響起除秀,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤窥翩,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后鳞仙,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡笔时,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年棍好,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片允耿。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡借笙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出较锡,到底是詐尸還是另有隱情业稼,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布蚂蕴,位于F島的核電站低散,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏骡楼。R本人自食惡果不足惜熔号,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鸟整。 院中可真熱鬧引镊,春花似錦、人聲如沸篮条。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)涉茧。三九已至赴恨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間降瞳,已是汗流浹背嘱支。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挣饥,地道東北人除师。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像扔枫,于是被迫代替她去往敵國(guó)和親汛聚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355