ArrayList 源碼解析

ArrayList 源碼解析

  • Arralist 內(nèi)部就是對(duì)Object[] elementData 進(jìn)行增刪改查的維護(hù)痴颊。
  • Arralist 線程非安全 安全的ArrayList 使用 List list = Collections.synchronizedList(new ArrayList(...));轿钠。
  • Arralist 每次擴(kuò)容是1.5倍液肌,默認(rèn)元素的個(gè)數(shù)是10個(gè)苛茂。
  • 注意源碼里面的 equals 判斷 如果傳入的對(duì)象沒(méi)有重寫(xiě)equals 則直接是比較的是 == 。
  • 刪除 插入指定位置的元素 代價(jià)比較高及老,這個(gè)位置以后的元素都要移動(dòng)位置豹悬。
  • 源碼中大量運(yùn)用了System.arraycopy

以下是基于jdk8 的部部分源碼

 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ù)組對(duì)象
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 * 
 * 默認(rèn)容量的空數(shù)組
 * 
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/**
 * 
 * ArraysList主要維護(hù)的對(duì)象所有的增刪改查都是操作這個(gè)數(shù)組
 * 
 * 
 */
transient Object[] elementData; // non-private to simplify nested class access

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

/**
 * 初始容量大于0 創(chuàng)建一個(gè)用戶指定的容量大小的數(shù)組
 * 等于 創(chuàng)建一個(gè)空數(shù)組
 * 小于0 拋出異常
 * 
 * 
 */
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}


public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}


public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

/**
 * 
 * 可以將數(shù)組的長(zhǎng)度調(diào)整為size.
 * 調(diào)整數(shù)組的大小
 */
public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}


/**
* 確保數(shù)組的內(nèi)容容量夠用
* 內(nèi)部數(shù)組 elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* 來(lái)確保 擴(kuò)容的元素大于等于10
*/
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}

/**
* 
* 如果擴(kuò)容的長(zhǎng)度大于內(nèi)部數(shù)組elementData的長(zhǎng)度 就要進(jìn)行擴(kuò)容
* 
*/
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

/**
 * 
 * 
 * 數(shù)組最大的容量
 * 
 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**
 * 
 * newCapacity = elementData.length + elementData.length/2 
 * newCapacity 是原來(lái)數(shù)組長(zhǎng)度的1.5倍
 *  通過(guò) Arrays.copyOf擴(kuò)容
 */
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);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

/**
 * 
 * 返回ArrayList的大小
 *
 */
public int size() {
    return size;
}

/**
 * 
 * 判斷ArrayList 是否為空
 */
public boolean isEmpty() {
    return size == 0;
}

/**
 * 
 * 判斷ArrayList 是否包含o
 * 
 * 
 */
public boolean contains(Object o) {
    return indexOf(o) >= 0;
}

/**
 * 查找 o 在elementData 當(dāng)中的索引,如果查找到返回索引分瘦,否則返回-1
 * 
 * 1蘸泻,如果包含多個(gè)o 只返回第一個(gè)索引
 * 2,這里使用的equals 比較嘲玫, 如果o對(duì)象 沒(méi)有重寫(xiě)equals  則是 == 比較
 * 
 */
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++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

/**
 * 查找 o 在elementData 當(dāng)中的最后的索引悦施,如果查找到返回索引,否則返回-1
 * 
 * 1去团,如果包含多個(gè)o 只返回最后一個(gè)索引
 * 2抡诞,這里使用的equals 比較穷蛹, 如果o對(duì)象 沒(méi)有重寫(xiě)equals  則是 == 比較
 * 
 * 
 */
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;
}

/**
 *
 *克隆對(duì)象 
 *
 *
 */
public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

/**
 * 轉(zhuǎn)換成數(shù)組
 * 這里沒(méi)有直接返回elementData
 */
public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}

/**
 * 轉(zhuǎn)換成指定類型的數(shù)組
 */
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    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];
}

/**
 * 
 * 獲取指定位置上的元素?cái)?shù)據(jù)
 * 1,驗(yàn)證index索引是否合法
 * 2沐绒,返回元素
 * 
 */
public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}

/**
 * 
 * 設(shè)置指定位置的元素?cái)?shù)據(jù)
 *
 * 返回沒(méi)有設(shè)置前 index 的數(shù)據(jù)
 * 
 */
public E set(int index, E element) {
    rangeCheck(index);

    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

/**
 * 
 *元素的末尾添加一個(gè)元素
 * 
 * 1.先驗(yàn)證數(shù)組是否要擴(kuò)容
 * 2.在elementData數(shù)組末尾添加元素
 */
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

/**
 * 在指定位置上添加元素
 * 1俩莽,檢查插入的位置是否合法
 * 2,擴(kuò)容處理
 * 3乔遮,指定位置之后的元素都要往后移動(dòng)(這個(gè)地方耗時(shí))
 * 4扮超,在elementData指定的位置上插入元素
 * 
 * 
 */
public void add(int index, E element) {
    rangeCheckForAdd(index);

    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}

/**
 * 刪除指定位置上的元素 并且返回
 * 1,判斷要?jiǎng)h除的index 是否合法蹋肮。
 * 2出刷,從index+1 的位置往前移動(dòng)數(shù)據(jù)  
 * 3,elementData 最后一個(gè)元素設(shè)置為null
 * 
 */
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;
}

/**
 * 刪除元素 成功返回ture 否則返回null
 * 
 * 1坯辩,如果傳入的對(duì)象是null 把elementData中所有的元素?cái)?shù)據(jù)是null的刪除
 * 2馁龟,非null,刪除 elementData中所有的元素?cái)?shù)據(jù)是o 的對(duì)象
 * 3漆魔,注意這里判斷是 使用的equals 方法坷檩,如果o對(duì)象沒(méi)有重寫(xiě)equals 方法
 *    則使用的 == 比較。如果要使用remove 刪除對(duì)象時(shí) 建議從寫(xiě)對(duì)象的equals方法
 *    和hashCode
 * 
 */
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;
}

/*
 * 刪除指定位置上的元素改抡,index后面的所有的元素往前移動(dòng)一位(比較耗時(shí))
 * elementData 數(shù)組的最后一個(gè)元素 設(shè)置為null
 */
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
}

/**
 * 刪除所有的元素
 * 所有的elementData 元素設(shè)置為null
 * 設(shè)置size = 0
 */
public void clear() {
    modCount++;

    // clear to let GC do its work
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}

/**
 * 在elementData數(shù)組末尾添加  c 集合矢炼,如果添加的結(jié)合不為空返回false
 * 
 * 1,先把c集合轉(zhuǎn)換為數(shù)組
 * 2阿纤,驗(yàn)證elementData是否需要擴(kuò)容
 * 3句灌,使用System.arraycopy 把c集合添加到elementData 數(shù)組中
 * 
 * 
 *c 如果是null 則會(huì)拋出NullPointerException異常
 * 
 * 
 * 
 */
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;
}

/**
 * 在elementData數(shù)組的index后添加  c 集合,如果添加的結(jié)合不為空返回false
 * 1欠拾,驗(yàn)證index 是否合法
 * 2胰锌,集合c 轉(zhuǎn)換為 Object[] 
 * 3,elementData驗(yàn)證是否需要擴(kuò)容
 * 4藐窄,把elementData 數(shù)組從index 位置 移動(dòng)numMoved位 使elementData
 *    空出numNew個(gè)位置
 * 5资昧,把c集合插入上面空出的位置
 * 
 * 
 * 有可能拋出IndexOutOfBoundsException  NullPointerException
 * 
 * 
 * 
 */
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;
}

/**
 * 刪除elementData數(shù)組 fromIndex到toIndex的元素
 * 
 * 1,用 toIndex+1 的位置的元素 往前移動(dòng)。
 * 2枷邪,把 size - (toIndex-fromIndex) 開(kāi)始到 size位置的元素置為null
 * 3,修改size的值
 *
 * 
 * 
 * 如果 romIndex < 0 || fromIndex >= size() 
 * || toIndex > size() || toIndex < fromIndex
 * 會(huì)拋出IndexOutOfBoundsException 
 * 
 * 
 */
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;
}

/**
 * 
 * 查看index 是否越界
 * 
 * 
 */
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}



/**
 * 
 * 刪除 傳入集合里面包含的數(shù)據(jù)
 * 只要?jiǎng)h除一個(gè)及以上返回true
 * false 表示沒(méi)有元素刪除
 */
public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}

/**
 * 
 * 返回ArrayList 中包含c 集合的元素
 * 1榛搔,執(zhí)行retainAll 會(huì)把其他的元素刪除掉,只剩 Arralist 和c 集合共同包含的元素
 *  Arralist  =  1东揣,2践惑,3,4
 *  c = 2,3
 *  執(zhí)行retainAll后  Arralist = 1嘶卧,4
 * 使用此方法注意ArrayList的變化
 */
public boolean retainAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, true);
}

/**
*
* 此算法很精妙
*
* 尤其
* if (c.contains(elementData[r]) == complement)
*               elementData[w++] = elementData[r];
*/
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;
        }
        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;
}
 
 }
arraylist.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末尔觉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子芥吟,更是在濱河造成了極大的恐慌侦铜,老刑警劉巖专甩,帶你破解...
    沈念sama閱讀 211,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異钉稍,居然都是意外死亡涤躲,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)贡未,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)种樱,“玉大人,你說(shuō)我怎么就攤上這事俊卤∧奂罚” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,435評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵消恍,是天一觀的道長(zhǎng)岂昭。 經(jīng)常有香客問(wèn)我,道長(zhǎng)狠怨,這世上最難降的妖魔是什么约啊? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,509評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮佣赖,結(jié)果婚禮上棍苹,老公的妹妹穿的比我還像新娘。我一直安慰自己茵汰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布孽鸡。 她就那樣靜靜地躺著蹂午,像睡著了一般。 火紅的嫁衣襯著肌膚如雪彬碱。 梳的紋絲不亂的頭發(fā)上豆胸,一...
    開(kāi)封第一講書(shū)人閱讀 49,837評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音巷疼,去河邊找鬼晚胡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嚼沿,可吹牛的內(nèi)容都是我干的估盘。 我是一名探鬼主播,決...
    沈念sama閱讀 38,987評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼骡尽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼遣妥!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起攀细,我...
    開(kāi)封第一講書(shū)人閱讀 37,730評(píng)論 0 267
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤箫踩,失蹤者是張志新(化名)和其女友劉穎爱态,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體境钟,經(jīng)...
    沈念sama閱讀 44,194評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锦担,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了慨削。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洞渔。...
    茶點(diǎn)故事閱讀 38,664評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖理盆,靈堂內(nèi)的尸體忽然破棺而出痘煤,到底是詐尸還是另有隱情,我是刑警寧澤猿规,帶...
    沈念sama閱讀 34,334評(píng)論 4 330
  • 正文 年R本政府宣布衷快,位于F島的核電站,受9級(jí)特大地震影響姨俩,放射性物質(zhì)發(fā)生泄漏蘸拔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評(píng)論 3 313
  • 文/蒙蒙 一环葵、第九天 我趴在偏房一處隱蔽的房頂上張望调窍。 院中可真熱鬧,春花似錦张遭、人聲如沸邓萨。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,764評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)缔恳。三九已至,卻和暖如春洁闰,著一層夾襖步出監(jiān)牢的瞬間歉甚,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,997評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工扑眉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纸泄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,389評(píng)論 2 360
  • 正文 我出身青樓腰素,卻偏偏與公主長(zhǎng)得像聘裁,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子耸弄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評(píng)論 2 349

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