ArrayList源碼解析

ArrayList簡介

ArrayList底層是數(shù)組隊(duì)列,相當(dāng)于動(dòng)態(tài)數(shù)組辟癌。與java中的數(shù)組相比,它的長度能動(dòng)態(tài)增長荐捻。在增加大量元素前愿待,可以使用ensureCapacity操作來增加ArrList實(shí)例的容量。這可以減少遞增式再分配的數(shù)量靴患。
它繼承與AbstractList仍侥,實(shí)現(xiàn)ListRandomAccess鸳君,Cloneable农渊,java.io.Serializable這些接口
ArrayList 繼承了AbstractList,實(shí)現(xiàn)了List或颊。它是一個(gè)數(shù)組隊(duì)列砸紊,提供了相關(guān)的添加、刪除囱挑、修改醉顽、遍歷等功能。

  • ArrayList 實(shí)現(xiàn)了RandomAccess 接口平挑, RandomAccess 是一個(gè)標(biāo)志接口游添,表明實(shí)現(xiàn)這個(gè)這個(gè)接口的 List 集合是支持快速隨機(jī)訪問的系草。在 ArrayList 中,我們即可以通過元素的序號(hào)快速獲取元素對(duì)象唆涝,這就是快速隨機(jī)訪問找都。
  • ArrayList 實(shí)現(xiàn)了Cloneable 接口,即覆蓋了函數(shù) clone()廊酣,能被克隆能耻。
  • ArrayList 實(shí)現(xiàn)java.io.Serializable 接口,這意味著ArrayList支持序列化亡驰,能通過序列化去傳輸晓猛。
  • 和 Vector 不同,ArrayList 中的操作不是線程安全的凡辱!所以戒职,建議在單線程中才使用 ArrayList,而在多線程中可以選擇 Vector 或者 CopyOnWriteArrayList煞茫。
ArrayList核心源碼
package java.util;

import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;


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

    /**
     * 默認(rèn)初始容量大小
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 空數(shù)組(用于空實(shí)例)帕涌。
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

     //用于默認(rèn)大小空實(shí)例的共享空數(shù)組實(shí)例摄凡。
      //我們把它從EMPTY_ELEMENTDATA數(shù)組中區(qū)分出來续徽,以知道在添加第一個(gè)元素時(shí)容量需要增加多少艺演。
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 保存ArrayList數(shù)據(jù)的數(shù)組
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * ArrayList 所包含的元素個(gè)數(shù)
     */
    private int size;

    /**
     * 帶初始容量參數(shù)的構(gòu)造函數(shù)广料。(用戶自己指定容量)
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            //創(chuàng)建initialCapacity大小的數(shù)組
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //創(chuàng)建空數(shù)組
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    /**
     *默認(rèn)構(gòu)造函數(shù),DEFAULTCAPACITY_EMPTY_ELEMENTDATA 為0.初始化為10凿菩,也就是說初始其實(shí)是空數(shù)組 當(dāng)添加第一個(gè)元素的時(shí)候數(shù)組容量才變成10
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**
     * 構(gòu)造一個(gè)包含指定集合的元素的列表床绪,按照它們由集合的迭代器返回的順序客情。
     */
    public ArrayList(Collection<? extends E> c) {
        //
        elementData = c.toArray();
        //如果指定集合元素個(gè)數(shù)不為0
        if ((size = elementData.length) != 0) {
            // c.toArray 可能返回的不是Object類型的數(shù)組所以加上下面的語句用于判斷,
            //這里用到了反射里面的getClass()方法
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // 用空數(shù)組代替
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

    /**
     * 修改這個(gè)ArrayList實(shí)例的容量是列表的當(dāng)前大小癞己。 應(yīng)用程序可以使用此操作來最小化ArrayList實(shí)例的存儲(chǔ)膀斋。 
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }
//下面是ArrayList的擴(kuò)容機(jī)制
//ArrayList的擴(kuò)容機(jī)制提高了性能,如果每次只擴(kuò)充一個(gè)痹雅,
//那么頻繁的插入會(huì)導(dǎo)致頻繁的拷貝仰担,降低性能,而ArrayList的擴(kuò)容機(jī)制避免了這種情況绩社。
    /**
     * 如有必要摔蓝,增加此ArrayList實(shí)例的容量,以確保它至少能容納元素的數(shù)量
     * @param   minCapacity   所需的最小容量
     */
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }
   //得到最小擴(kuò)容量
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
              // 獲取默認(rèn)的容量和傳入?yún)?shù)的較大值
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
  //判斷是否需要擴(kuò)容
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            //調(diào)用grow方法進(jìn)行擴(kuò)容愉耙,調(diào)用此方法代表已經(jīng)開始擴(kuò)容了
            grow(minCapacity);
    }

    /**
     * 要分配的最大數(shù)組大小
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * ArrayList擴(kuò)容的核心方法贮尉。
     */
    private void grow(int minCapacity) {
        // oldCapacity為舊容量,newCapacity為新容量
        int oldCapacity = elementData.length;
        //將oldCapacity 右移一位朴沿,其效果相當(dāng)于oldCapacity /2猜谚,
        //我們知道位運(yùn)算的速度遠(yuǎn)遠(yuǎn)快于整除運(yùn)算败砂,整句運(yùn)算式的結(jié)果就是將新容量更新為舊容量的1.5倍,
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //然后檢查新容量是否大于最小需要容量龄毡,若還是小于最小需要容量吠卷,那么就把最小需要容量當(dāng)作數(shù)組的新容量,
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //再檢查新容量是否超出了ArrayList所定義的最大容量沦零,
        //若超出了祭隔,則調(diào)用hugeCapacity()來比較minCapacity和 MAX_ARRAY_SIZE,
        //如果minCapacity大于MAX_ARRAY_SIZE路操,則新容量則為Interger.MAX_VALUE疾渴,否則,新容量大小則為 MAX_ARRAY_SIZE屯仗。
        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);
    }
    //比較minCapacity和 MAX_ARRAY_SIZE
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

    /**
     *返回此列表中的元素?cái)?shù)搞坝。 
     */
    public int size() {
        return size;
    }

    /**
     * 如果此列表不包含元素,則返回 true 魁袜。
     */
    public boolean isEmpty() {
        //注意=和==的區(qū)別
        return size == 0;
    }

    /**
     * 如果此列表包含指定的元素桩撮,則返回true 。
     */
    public boolean contains(Object o) {
        //indexOf()方法:返回此列表中指定元素的首次出現(xiàn)的索引峰弹,如果此列表不包含此元素店量,則為-1 
        return indexOf(o) >= 0;
    }

    /**
     *返回此列表中指定元素的首次出現(xiàn)的索引,如果此列表不包含此元素鞠呈,則為-1 
     */
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                //equals()方法比較
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    /**
     * 返回此列表中指定元素的最后一次出現(xiàn)的索引融师,如果此列表不包含元素,則返回-1蚁吝。.
     */
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    /**
     * 返回此ArrayList實(shí)例的淺拷貝旱爆。 (元素本身不被復(fù)制。) 
     */
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            //Arrays.copyOf功能是實(shí)現(xiàn)數(shù)組的復(fù)制窘茁,返回復(fù)制后的數(shù)組怀伦。參數(shù)是被復(fù)制的數(shù)組和復(fù)制的長度
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // 這不應(yīng)該發(fā)生,因?yàn)槲覀兪强梢钥寺〉?            throw new InternalError(e);
        }
    }

    /**
     *以正確的順序(從第一個(gè)到最后一個(gè)元素)返回一個(gè)包含此列表中所有元素的數(shù)組山林。 
     *返回的數(shù)組將是“安全的”房待,因?yàn)樵摿斜聿槐A魧?duì)它的引用。 (換句話說捌朴,這個(gè)方法必須分配一個(gè)新的數(shù)組)吴攒。
     *因此,調(diào)用者可以自由地修改返回的數(shù)組砂蔽。 此方法充當(dāng)基于陣列和基于集合的API之間的橋梁洼怔。
     */
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

    /**
     * 以正確的順序返回一個(gè)包含此列表中所有元素的數(shù)組(從第一個(gè)到最后一個(gè)元素); 
     *返回的數(shù)組的運(yùn)行時(shí)類型是指定數(shù)組的運(yùn)行時(shí)類型。 如果列表適合指定的數(shù)組左驾,則返回其中镣隶。 
     *否則极谊,將為指定數(shù)組的運(yùn)行時(shí)類型和此列表的大小分配一個(gè)新數(shù)組。 
     *如果列表適用于指定的數(shù)組安岂,其余空間(即數(shù)組的列表數(shù)量多于此元素)轻猖,則緊跟在集合結(jié)束后的數(shù)組中的元素設(shè)置為null 。
     *(這僅在調(diào)用者知道列表不包含任何空元素的情況下才能確定列表的長度域那。) 
     */
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // 新建一個(gè)運(yùn)行時(shí)類型的數(shù)組咙边,但是ArrayList數(shù)組的內(nèi)容
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
            //調(diào)用System提供的arraycopy()方法實(shí)現(xiàn)數(shù)組之間的復(fù)制
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

    // Positional Access Operations

    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

    /**
     * 返回此列表中指定位置的元素。
     */
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

    /**
     * 用指定的元素替換此列表中指定位置的元素次员。 
     */
    public E set(int index, E element) {
        //對(duì)index進(jìn)行界限檢查
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        //返回原來在這個(gè)位置的元素
        return oldValue;
    }

    /**
     * 將指定的元素追加到此列表的末尾败许。 
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //這里看到ArrayList添加元素的實(shí)質(zhì)就相當(dāng)于為數(shù)組賦值
        elementData[size++] = e;
        return true;
    }

    /**
     * 在此列表中的指定位置插入指定的元素。 
     *先調(diào)用 rangeCheckForAdd 對(duì)index進(jìn)行界限檢查淑蔚;然后調(diào)用 ensureCapacityInternal 方法保證capacity足夠大市殷;
     *再將從index開始之后的所有成員后移一個(gè)位置;將element插入index位置刹衫;最后size加1醋寝。
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //arraycopy()這個(gè)實(shí)現(xiàn)數(shù)組之間復(fù)制的方法一定要看一下,下面就用到了arraycopy()方法實(shí)現(xiàn)數(shù)組自己復(fù)制自己
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

    /**
     * 刪除該列表中指定位置的元素带迟。 將任何后續(xù)元素移動(dòng)到左側(cè)(從其索引中減去一個(gè)元素)音羞。 
     */
    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;
    }

    /**
     * 從列表中刪除指定元素的第一個(gè)出現(xiàn)(如果存在)。 如果列表不包含該元素邮旷,則它不會(huì)更改黄选。
     *返回true蝇摸,如果此列表包含指定的元素
     */
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

    /*
     * Private remove method that skips bounds checking and does not
     * return the value removed.
     */
    private void fastRemove(int index) {
        modCount++;
        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
    }

    /**
     * 從列表中刪除所有元素婶肩。 
     */
    public void clear() {
        modCount++;

        // 把數(shù)組中所有的元素的值設(shè)為null
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

    /**
     * 按指定集合的Iterator返回的順序?qū)⒅付现械乃性刈芳拥酱肆斜淼哪┪病?     */
    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

    /**
     * 將指定集合中的所有元素插入到此列表中,從指定的位置開始貌夕。
     */
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount

        int numMoved = size - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);

        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }

    /**
     * 從此列表中刪除所有索引為fromIndex (含)和toIndex之間的元素律歼。
     *將任何后續(xù)元素移動(dòng)到左側(cè)(減少其索引)。
     */
    protected void removeRange(int fromIndex, int toIndex) {
        modCount++;
        int numMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved);

        // clear to let GC do its work
        int newSize = size - (toIndex-fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }

    /**
     * 檢查給定的索引是否在范圍內(nèi)啡专。
     */
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /**
     * add和addAll使用的rangeCheck的一個(gè)版本
     */
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /**
     * 返回IndexOutOfBoundsException細(xì)節(jié)信息
     */
    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

    /**
     * 從此列表中刪除指定集合中包含的所有元素险毁。 
     */
    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        //如果此列表被修改則返回true
        return batchRemove(c, false);
    }

    /**
     * 僅保留此列表中包含在指定集合中的元素。
     *換句話說们童,從此列表中刪除其中不包含在指定集合中的所有元素畔况。 
     */
    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }


    /**
     * 從列表中的指定位置開始,返回列表中的元素(按正確順序)的列表迭代器慧库。
     *指定的索引表示初始調(diào)用將返回的第一個(gè)元素為next 跷跪。 初始調(diào)用previous將返回指定索引減1的元素。 
     *返回的列表迭代器是fail-fast 齐板。 
     */
    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }

    /**
     *返回列表中的列表迭代器(按適當(dāng)?shù)捻樞颍?
     *返回的列表迭代器是fail-fast 吵瞻。
     */
    public ListIterator<E> listIterator() {
        return new ListItr(0);
    }

    /**
     *以正確的順序返回該列表中的元素的迭代器葛菇。 
     *返回的迭代器是fail-fast 。 
     */
    public Iterator<E> iterator() {
        return new Itr();
    }

源碼分析
System.arraycopy()和Arrays.copyOf()方法

通過上面源碼我們發(fā)現(xiàn)這兩個(gè)實(shí)現(xiàn)數(shù)組復(fù)制的方法被廣泛使用而且很多地方都特別巧妙橡羞。比如下面add(int index, E element)方法就很巧妙的用到了arraycopy()方法讓數(shù)組自己復(fù)制自己實(shí)現(xiàn)讓index開始之后的所有成員后移一個(gè)位置:

    /**
     * 在此列表中的指定位置插入指定的元素眯停。 
     *先調(diào)用 rangeCheckForAdd 對(duì)index進(jìn)行界限檢查;然后調(diào)用 ensureCapacityInternal 方法保證capacity足夠大卿泽;
     *再將從index開始之后的所有成員后移一個(gè)位置莺债;將element插入index位置;最后size加1签夭。
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //arraycopy()方法實(shí)現(xiàn)數(shù)組自己復(fù)制自己
        //elementData:源數(shù)組;index:源數(shù)組中的起始位置;elementData:目標(biāo)數(shù)組九府;index + 1:目標(biāo)數(shù)組中的起始位置; size - index:要復(fù)制的數(shù)組元素的數(shù)量覆致;
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
        elementData[index] = element;
        size++;
    }
又如toArray()方法中用到了copyOf()方法
    /**
     *以正確的順序(從第一個(gè)到最后一個(gè)元素)返回一個(gè)包含此列表中所有元素的數(shù)組侄旬。 
     *返回的數(shù)組將是“安全的”,因?yàn)樵摿斜聿槐A魧?duì)它的引用煌妈。 (換句話說儡羔,這個(gè)方法必須分配一個(gè)新的數(shù)組)。
     *因此璧诵,調(diào)用者可以自由地修改返回的數(shù)組汰蜘。 此方法充當(dāng)基于陣列和基于集合的API之間的橋梁。
     */
    public Object[] toArray() {
    //elementData:要復(fù)制的數(shù)組之宿;size:要復(fù)制的長度
        return Arrays.copyOf(elementData, size);
    }
兩者聯(lián)系與區(qū)別

聯(lián)系: 看兩者源代碼可以發(fā)現(xiàn)copyOf()內(nèi)部調(diào)用了System.arraycopy()方法 區(qū)別:

  1. arraycopy()需要目標(biāo)數(shù)組族操,將原數(shù)組拷貝到你自己定義的數(shù)組里,而且可以選擇拷貝的起點(diǎn)和長度以及放入新數(shù)組中的位置
  2. copyOf()是系統(tǒng)自動(dòng)在內(nèi)部新建一個(gè)數(shù)組比被,并返回該數(shù)組色难。
ArrayList 核心擴(kuò)容技術(shù)
    //下面是ArrayList的擴(kuò)容機(jī)制
    //ArrayList的擴(kuò)容機(jī)制提高了性能,如果每次只擴(kuò)充一個(gè)等缀,
    //那么頻繁的插入會(huì)導(dǎo)致頻繁的拷貝枷莉,降低性能,而ArrayList的擴(kuò)容機(jī)制避免了這種情況尺迂。
    /**
     * 如有必要笤妙,增加此ArrayList實(shí)例的容量,以確保它至少能容納元素的數(shù)量
     * @param   minCapacity   所需的最小容量
     */
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }
   //得到最小擴(kuò)容量
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
              // 獲取默認(rèn)的容量和傳入?yún)?shù)的較大值
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
    //判斷是否需要擴(kuò)容,上面兩個(gè)方法都要調(diào)用
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // 如果說minCapacity也就是所需的最小容量大于保存ArrayList數(shù)據(jù)的數(shù)組的長度的話噪裕,就需要調(diào)用grow(minCapacity)方法擴(kuò)容蹲盘。
        //這個(gè)minCapacity到底為多少呢?舉個(gè)例子在添加元素(add)方法中這個(gè)minCapacity的大小就為現(xiàn)在數(shù)組的長度加1
        if (minCapacity - elementData.length > 0)
            //調(diào)用grow方法進(jìn)行擴(kuò)容膳音,調(diào)用此方法代表已經(jīng)開始擴(kuò)容了
            grow(minCapacity);
    }



    /**
     * ArrayList擴(kuò)容的核心方法召衔。
     */
    private void grow(int minCapacity) {
       //elementData為保存ArrayList數(shù)據(jù)的數(shù)組
       ///elementData.length求數(shù)組長度elementData.size是求數(shù)組中的元素個(gè)數(shù)
        // oldCapacity為舊容量,newCapacity為新容量
        int oldCapacity = elementData.length;
        //將oldCapacity 右移一位严蓖,其效果相當(dāng)于oldCapacity /2薄嫡,
        //我們知道位運(yùn)算的速度遠(yuǎn)遠(yuǎn)快于整除運(yùn)算氧急,整句運(yùn)算式的結(jié)果就是將新容量更新為舊容量的1.5倍,
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //然后檢查新容量是否大于最小需要容量毫深,若還是小于最小需要容量吩坝,那么就把最小需要容量當(dāng)作數(shù)組的新容量,
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //再檢查新容量是否超出了ArrayList所定義的最大容量哑蔫,
        //若超出了钉寝,則調(diào)用hugeCapacity()來比較minCapacity和 MAX_ARRAY_SIZE,
        //如果minCapacity大于MAX_ARRAY_SIZE闸迷,則新容量則為Interger.MAX_VALUE嵌纲,否則,新容量大小則為 MAX_ARRAY_SIZE腥沽。
        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);
    }

擴(kuò)容機(jī)制代碼已經(jīng)做了詳細(xì)的解釋逮走。另外值得注意的是大家很容易忽略的一個(gè)運(yùn)算符:移位運(yùn)算符   簡介:移位運(yùn)算符就是在二進(jìn)制的基礎(chǔ)上對(duì)數(shù)字進(jìn)行平移。按照平移的方向和填充數(shù)字的規(guī)則分為三種:<<(左移)今阳、>>(帶符號(hào)右移)和>>>(無符號(hào)右移)师溅。   作用:對(duì)于大數(shù)據(jù)的2進(jìn)制運(yùn)算,位移運(yùn)算符比那些普通運(yùn)算符的運(yùn)算要快很多,因?yàn)槌绦騼H僅移動(dòng)一下而已,不去計(jì)算,這樣提高了效率,節(jié)省了資源   比如這里:int newCapacity = oldCapacity + (oldCapacity >> 1); 右移一位相當(dāng)于除2,右移n位相當(dāng)于除以 2 的 n 次方盾舌。這里 oldCapacity 明顯右移了1位所以相當(dāng)于oldCapacity /2墓臭。

另外需要注意的是:

  1. java 中的length 屬性是針對(duì)數(shù)組說的,比如說你聲明了一個(gè)數(shù)組,想知道這個(gè)數(shù)組的長度則用到了 length 這個(gè)屬性.
  2. java 中的length()方法是針對(duì)字 符串String說的,如果想看這個(gè)字符串的長度則用到 length()這個(gè)方法.
  3. java 中的size()方法是針對(duì)泛型集合說的,如果想看這個(gè)泛型有多少個(gè)元素,就調(diào)用此方法來查看!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市妖谴,隨后出現(xiàn)的幾起案子窿锉,更是在濱河造成了極大的恐慌,老刑警劉巖膝舅,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗡载,死亡現(xiàn)場離奇詭異,居然都是意外死亡铸史,警方通過查閱死者的電腦和手機(jī)鼻疮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門怯伊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來琳轿,“玉大人,你說我怎么就攤上這事耿芹≌复郏” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵吧秕,是天一觀的道長琉闪。 經(jīng)常有香客問我,道長砸彬,這世上最難降的妖魔是什么颠毙? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任斯入,我火速辦了婚禮,結(jié)果婚禮上蛀蜜,老公的妹妹穿的比我還像新娘刻两。我一直安慰自己,他們只是感情好滴某,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布磅摹。 她就那樣靜靜地躺著,像睡著了一般霎奢。 火紅的嫁衣襯著肌膚如雪户誓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天幕侠,我揣著相機(jī)與錄音帝美,去河邊找鬼。 笑死晤硕,一個(gè)胖子當(dāng)著我的面吹牛证舟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播窗骑,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼女责,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了创译?” 一聲冷哼從身側(cè)響起抵知,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎软族,沒想到半個(gè)月后刷喜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡立砸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年掖疮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颗祝。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡浊闪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出螺戳,到底是詐尸還是另有隱情搁宾,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布倔幼,位于F島的核電站盖腿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜翩腐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一鸟款、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧茂卦,春花似錦欠雌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至而咆,卻和暖如春霍比,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背暴备。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來泰國打工悠瞬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人涯捻。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓浅妆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親障癌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子凌外,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

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