ArrayList 源碼分析

ArrayList是在Java中最常用的集合之一,其本質(zhì)上可以當(dāng)做是一個(gè)可擴(kuò)容的數(shù)組,可以添加重復(fù)的數(shù)據(jù),也支持隨機(jī)訪問(wèn)

ArrayList的類定義

    public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

其中,RandomAccess、Cloneable、Serializable三個(gè)接口都屬于標(biāo)記接口,沒(méi)有任何需要手動(dòng)實(shí)現(xiàn)的方法

有人以為clone()方法來(lái)自于Cloneable接口,實(shí)際上clone()方法來(lái)自于Object類

  • RandomAccess接口表示ArrayList支持隨機(jī)訪問(wèn),即可以直接訪問(wèn)集合內(nèi)任意位置的元素
  • Cloneable接口表示ArrayList支持克隆,并重寫了克隆方法
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);
    }
}

從上方代碼第四行出可以看出,調(diào)用clone()方法時(shí),也重新創(chuàng)建了一個(gè)新的數(shù)組作為集合數(shù)據(jù)的容器,新舊兩個(gè)集合擁有各自的數(shù)據(jù)存儲(chǔ)的內(nèi)容空間,互不影響

  • Serializable接口表示ArrayList可序列化

除此之外, 父類AbstractList也提供了部分通用方法的實(shí)現(xiàn)。但是這些方法有很多都進(jìn)行了重寫,所以本文不會(huì)過(guò)多關(guān)注AbstractList類。但是它提供了一個(gè)非常重要的成員變量:modCount,表示集合長(zhǎng)度被修改的次數(shù),在遍歷集合段落中會(huì)詳細(xì)講解它的作用

ArrayList 的成員變量分析

ArrayList的成員變量包含

// 序列化ID
private static final long serialVersionUID = 8683452581122892189L;

// 集合的默認(rèn)容量
private static final int DEFAULT_CAPACITY = 10;

// 用于初始化elementData的空數(shù)組 
private static final Object[] EMPTY_ELEMENTDATA = {};

// 默認(rèn)容量下用于初始化elementData的空數(shù)組 
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

// 存放實(shí)際元素的數(shù)組
transient Object[] elementData;

// 集合的大小
private int size;

// 集合的最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

根據(jù)源碼,我們可以得到兩個(gè)比較直觀的信息:

  1. 集合的默認(rèn)容量是10,即調(diào)用無(wú)參構(gòu)造器生成的ArrayList,在不擴(kuò)容的情況下,最多能夠存儲(chǔ)10個(gè)數(shù)據(jù)
  2. 集合的本質(zhì)是一個(gè)類型為Object的數(shù)組

要有一個(gè)值得注意的地方,成員變量中包含兩個(gè)用于初始化elementData的空數(shù)組:EMPTY_ELEMENTDATADEFAULTCAPACITY_EMPTY_ELEMENTDATA

在實(shí)例化ArrayList的時(shí)候,如果指定capacity(容量)為0,則使用EMPTY_ELEMENTDATA來(lái)初始化elementData;沒(méi)有指定capacity,也就是使用默認(rèn)容量capacity = 10的情況下,則使用DEFAULTCAPACITY_EMPTY_ELEMENTDATA來(lái)初始化elementData

為什么要根據(jù)不同的情況使用不同的空接口。因?yàn)锳rrayList要根據(jù)不同的情況進(jìn)行擴(kuò)容。通過(guò)new ArrayList(0)構(gòu)造的集合,其容量就是0;但是通過(guò)new ArrayList()構(gòu)造的集合,雖然初始化后elementData也是一個(gè)空數(shù)組,但是在添加第一個(gè)元素后,其會(huì)立即擴(kuò)容為一個(gè)容量為10(默認(rèn)capacity)的數(shù)組。這是兩種不同的處理方式,所以要區(qū)分不同的空數(shù)組對(duì)象。在后續(xù)的構(gòu)造函數(shù)添加元素段落中還會(huì)繼續(xù)講到

最后,為什么集合的最大容量是Integer.MAX_VALUE — 8?為什么要節(jié)省這8個(gè)容量?因?yàn)橛幸恍┨摂M機(jī)會(huì)在數(shù)組中保留一些頭信息或是描述信息,嘗試分配更大的數(shù)組可能會(huì)導(dǎo)致OutOfMemoryError

構(gòu)造器分析

ArrayList擁有三個(gè)構(gòu)造器,它們本質(zhì)上都是在對(duì)內(nèi)部的elementData進(jìn)行初始化操作

  • 無(wú)參構(gòu)造器
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

這是最簡(jiǎn)單的構(gòu)造器,僅僅只是將elementData指向常量DEFAULTCAPACITY_EMPTY_ELEMENTDATA,以便于在添加第一個(gè)元素時(shí),擴(kuò)容至默認(rèn)容量capacity = 10的大小


  • 顯式設(shè)置初始化容量的構(gòu)造器
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);
    }
}

這個(gè)構(gòu)造器首先需要保證手動(dòng)指定的容量大于0,否則會(huì)拋出IllegalArgumentException異常;其次,判斷手動(dòng)指定的容量是否等于0,如果是,則直接將elementData指向靜態(tài)常量DEFAULTCAPACITY_EMPTY_ELEMENTDATA,如果不是,則創(chuàng)建一個(gè)跟指定容量相同大小的Object類型的數(shù)組作為elementData即可


  • 基于另一個(gè)集合創(chuàng)建ArrayList的構(gòu)造器
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

這個(gè)構(gòu)造器相對(duì)比較復(fù)雜。首先,將參數(shù)集合轉(zhuǎn)換為數(shù)組對(duì)象。接下來(lái),判斷新數(shù)組對(duì)象是否包含元素,對(duì)應(yīng)源碼的第3行。如果沒(méi)有元素,則直接將elementData指向靜態(tài)常量DEFAULTCAPACITY_EMPTY_ELEMENTDATA。如果數(shù)組對(duì)象包含元素,則要判定數(shù)組對(duì)象的類型是否屬于Object數(shù)組類型(由于不同集合有不同的toArray方法的實(shí)現(xiàn),所以toArray方法不一定返回的是Object類型的數(shù)組)。在類型不屬于Object數(shù)組類型時(shí),根據(jù)當(dāng)前的數(shù)組對(duì)象的大小和實(shí)際元素,復(fù)制一個(gè)新的Object類型的數(shù)組作為elementData

重要方法

添加元素

在開(kāi)始分析添加元素的方法之前,我們需要先來(lái)分析幾個(gè)工具方法

  • 確保集合內(nèi)容容量充足的前置方法
/**
 * 確保集合內(nèi)容容量充足的前置方法
 * @Param minCapacity 調(diào)用者指定的最小容量
 */
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

在添加元素時(shí),ArrayList會(huì)判斷當(dāng)前容量是否充足,在不充足的情況下進(jìn)行擴(kuò)容。ensureCapacityInternal(int)方法只是用來(lái)獲取到當(dāng)前所需要的最小容量。正如源碼所展示的,當(dāng)前所需要的容量并不一定是方法調(diào)用者傳入的minCapacity的值,因?yàn)楫?dāng)集合通過(guò)無(wú)參構(gòu)造器創(chuàng)建時(shí),即elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA時(shí),它的容量至少要達(dá)到10(默認(rèn)容量的大?。?strong>DEFAULT_CAPACITY)。

拿到最小需要的容量后,判斷當(dāng)前集合是否滿足條件,到底需不需要擴(kuò)容,則交給了ensureExplicitCapacity(int)方法來(lái)處理


  • 判斷集合是否需要擴(kuò)容的方法
/**
 * 判斷當(dāng)前集合是否需要擴(kuò)容的方法
 * @Param minCapacity 實(shí)際需要的最小容量
 */
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
  if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

之前提到了ArrayList從AbstractList父類中繼承了一個(gè)非常重要的字段:modCount,這個(gè)字段表示的是集合內(nèi)部數(shù)組對(duì)象長(zhǎng)度可能被修改的次數(shù),在所有有可能改變數(shù)組對(duì)象長(zhǎng)度的方法中,modCount都會(huì)進(jìn)行自增操作,用于保證集合迭代時(shí)不會(huì)因?yàn)榧系拈L(zhǎng)度發(fā)生改變而出現(xiàn)奇怪的錯(cuò)誤,其具體的用法會(huì)在后續(xù)遍歷元素段落中詳細(xì)分析

只要實(shí)際需要的最小容量大于當(dāng)前集合的容量,就需要擴(kuò)容。具體擴(kuò)容的操作交給grow(int)來(lái)處理


  • 對(duì)集合進(jìn)行擴(kuò)容的方法
/**
 * 實(shí)際需要的最小容量
 * @Param minCapacity 實(shí)際需要的最小容量
 */
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

對(duì)集合進(jìn)行擴(kuò)容,我們需要知道擴(kuò)容后的容量是多少?雖然當(dāng)前需要的最小容量是minCapacity,但是如果minCapacity小于原始容量的1.5倍,則ArrayList認(rèn)為這個(gè)minCapacity的容量也是不安全的,很有可能會(huì)進(jìn)行第二次擴(kuò)容。為了減少擴(kuò)容帶來(lái)的消耗,此時(shí)ArrayList認(rèn)為擴(kuò)容后的容量應(yīng)該為原始容量的1.5倍

不管是選擇minCapacity還是原始容量的1.5倍作為擴(kuò)容后的容量,都會(huì)存在一種特殊情況:擴(kuò)容后的容量大于了集合允許的最大容量(MAX_ARRAY_SIZE),這種情況應(yīng)該怎么處理?

前文說(shuō)到,集合的最大容量為Integer.MAX_VALUE — 8,這節(jié)省的8個(gè)容量是用于某些虛擬機(jī)在數(shù)組中保存一些頭信息或描述信息。如果集合的容量實(shí)在不夠,那只能把原本節(jié)省下來(lái)的8個(gè)容量拿來(lái)使用,這也意味著,在某些虛擬機(jī)環(huán)境下,這樣的操作會(huì)導(dǎo)致OutOfMemoryError錯(cuò)誤。

這個(gè)操作是由hugeCapacity(int)方法來(lái)完成的,由于這個(gè)方法非常簡(jiǎn)單,在這里就不對(duì)其做單獨(dú)的分析了

確定擴(kuò)容后的容量后,根據(jù)這個(gè)容量創(chuàng)建一個(gè)新的數(shù)組,并把原始數(shù)據(jù)的數(shù)據(jù)拷貝過(guò)來(lái),集合的擴(kuò)容也就完成了

到這里可以看出,擴(kuò)容本身就是一種低效率的操作(除了要開(kāi)辟新的內(nèi)存空間外,還得把數(shù)據(jù)一個(gè)一個(gè)的復(fù)制到新的空間中),并且隨著原始數(shù)據(jù)增加,操作的速度也會(huì)越來(lái)越慢(copy10個(gè)數(shù)據(jù)絕對(duì)比copy1個(gè)數(shù)據(jù)慢),所以最好能在構(gòu)造ArrayList時(shí)就預(yù)估好容量的大小,避免擴(kuò)容帶來(lái)的開(kāi)銷


現(xiàn)在我們?cè)賮?lái)分析添加元素的方法就比較簡(jiǎn)單了

// 在集合的末尾添加一個(gè)元素
public boolean add(E e) {
    ensureCapacityInternal(size + 1);
    elementData[size++] = e;
    return true;
}

// 在集合的指定位置,添加一個(gè)元素
public void add(int index, E element) {
    rangeCheckForAdd(index);
    ensureCapacityInternal(size + 1);
    System.arraycopy(elementData, index, elementData, index + 1, size - index);
    elementData[index] = element;
    size++;
}

不管使用的是哪個(gè)方法,都需要判斷集合是否能夠容納size + 1容量的數(shù)據(jù)。如果達(dá)不到要求就開(kāi)始擴(kuò)容。其次,我們發(fā)現(xiàn)在指定位置添加元素是一件非常麻煩的事情,因?yàn)閺闹付ㄎ恢瞄_(kāi)始到集合末尾的數(shù)據(jù),都得往后移動(dòng)一位。所以在使用ArrayList的時(shí)候,盡量不要在集合中的某一個(gè)位置添加元素。如果確實(shí)存在這種需求,那么可以考慮使用LinkedList而不是ArrayList(后續(xù)我們也會(huì)對(duì)LinkedList的源碼進(jìn)行分析)

這里有個(gè)很簡(jiǎn)單的方法rangeCheckForAdd(int),其用來(lái)判斷參數(shù)index是否合法,不對(duì)其做單獨(dú)的分析

獲取元素

public E get(int index) {
    rangeCheck(index);
    return elementData(index);
}

E elementData(int index) {
    return (E) elementData[index];
}

判斷指定坐標(biāo)是否越界(依賴于非常簡(jiǎn)單的rangeCheck(int)方法),然后直接從內(nèi)部數(shù)據(jù)中獲取數(shù)據(jù)

刪除元素

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;     
    return oldValue;
}

刪除方法遇到了跟add(int, E)方法同樣的問(wèn)題,即要把指定位置開(kāi)始至整個(gè)集合末尾的所有元素向前移動(dòng)一位

到此可以看出,對(duì)于ArrayList來(lái)說(shuō),添加元素、刪除元素都不是那么便捷的事情,ArrayList的優(yōu)勢(shì)還是在于能夠快速的訪問(wèn)元素

由于現(xiàn)在較操作前少了一個(gè)元素,所以在移動(dòng)元素之后需要把當(dāng)前集合的最后一位元素的值設(shè)置為null


還有一個(gè)刪除元素的方法

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;
}

這個(gè)方法本質(zhì)上也是查找到指定元素在集合中的位置,再根據(jù)這個(gè)位置使用fastRemove(int)方法來(lái)執(zhí)行刪除操作

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; 
}

fastRemove(int)方法的原理跟remove(int)方法是一致的

注意,刪除操作也會(huì)改變集合的長(zhǎng)度,所以每個(gè)刪除方法中都有modCount++操作

遍歷元素

在JDK1.5之后,通常使用foreach循環(huán)(也叫增強(qiáng)for循環(huán))來(lái)對(duì)集合進(jìn)行遍歷


List<E> list = new ArrayList<>();
for(E e: list) {
    System.out.println(e);
}

foreach循環(huán)本質(zhì)上是在調(diào)用迭代器

List<E> list = new ArrayList<>();
Iterator<E> iter = list.iterator();
while(iter.hasNext()) {
    System.out.println(iter.next());
}

ArrayList調(diào)用iterator()方法返還的是一個(gè)類型為ArrayList$Itr的迭代器。這個(gè)類是ArrayList中的一個(gè)私有內(nèi)部類

private class Itr implements Iterator<E> {
    int cursor; // 下一個(gè)返回的元素的索引
    int lastRet = -1; // 上一次返還的元素的索引,如果沒(méi)有則為-1
    int expectedModCount = modCount; // 預(yù)期的集合長(zhǎng)度被修改的次數(shù)
}

終于要到modCount的用法了

當(dāng)一個(gè)modCount為0(長(zhǎng)度沒(méi)有被修改過(guò))的ArrayList調(diào)用Iterator()方法后,我們會(huì)得到這樣的一個(gè)Itr對(duì)象

// 偽代碼
Itr: {
    cursor: 0,
    lastRet: -1,
    expectedModCount: 0
}

此時(shí)我們可以調(diào)用hasNext()方法來(lái)判斷是否還有元素未訪問(wèn),即是否能夠繼續(xù)迭代

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

如果上一次訪問(wèn)的元素是集合的最后一個(gè)元素,即上一次訪問(wèn)的元素索引為size - 1,那么就不能再繼續(xù)迭代了。這種情況下,因?yàn)閏ursor屬性代表下一次訪問(wèn)元素的索引,所以可以說(shuō),cursor的值等于上一次訪問(wèn)元素的索引 + 1,也就是說(shuō)當(dāng)cursor = (size - 1) + 1時(shí),就可以表示集合已經(jīng)迭代完畢。反過(guò)來(lái),當(dāng)cursor != (size -1) + 1時(shí),就表示集合還可以繼續(xù)迭代

當(dāng)我們通過(guò)hasNext()方法確定集合還能夠迭代時(shí),可以通過(guò)next()方法取出迭代的元素的值

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];
}

除去驗(yàn)證的代碼,重要的是,我們能夠看到,cursor始終指向下一次返回元素的索引,同時(shí),lastRet指向當(dāng)前返還元素的索引

假設(shè),此時(shí)有另一個(gè)程序?qū)Ξ?dāng)前集合中的某一處進(jìn)行了添加操作(調(diào)用了add(int, e)方法),如果對(duì)這樣的情況放任不管,那么迭代器迭代的數(shù)據(jù)肯定會(huì)有錯(cuò)誤。所以,有了一個(gè)方法:checkForComodification()來(lái)確保迭代時(shí),集合的長(zhǎng)度沒(méi)有發(fā)生改變

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

此時(shí),因?yàn)榧险{(diào)用了add(int, e)方法,所以集合的屬性modCount = modCount + 1,而迭代器的屬性是expectedModCount是在迭代器實(shí)例化的時(shí)候就已經(jīng)創(chuàng)建好的,expectedModCount = 0,因此,modCount != expectedModCount,表示迭代器生成之后,集合發(fā)生了長(zhǎng)度方面的改變,會(huì)影響集合的遍歷操作,拋出ConcurrentModificationException異常。從AbstractList處誕生的modCount屬性,一直到了這里才有了自己的用武之地

但是,有些時(shí)候,我們確實(shí)需要在遍歷的過(guò)程中操作數(shù)據(jù),比如說(shuō):遍歷某個(gè)集合,把符合某種條件的數(shù)據(jù)刪除掉。對(duì)于這樣的情況,迭代器提供了一個(gè)通過(guò)它自己來(lái)修改集合元素的方法:remove()

注意,迭代器只提供了對(duì)集合元素進(jìn)行刪除操作的方法,沒(méi)有添加元素的方法

public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    // 確保集合本身沒(méi)有被其他方式修改過(guò)
    checkForComodification();
    try {
        // 刪除上一次返回的元素
        ArrayList.this.remove(lastRet);
        cursor = lastRet;
        lastRet = -1;
        // modCount被修改了,expectedModCount也要跟著修改
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}

值得注意的是,執(zhí)行刪除操作后,lastRet的值變?yōu)榱?1,所以,不能通過(guò)迭代器進(jìn)行連續(xù)的刪除操作

List<E> list = new ArrayList<>();
Iterator<E> iter = list.iterator();

// 這是錯(cuò)誤的做法
iter.next();
iter.remove();
// 連續(xù)刪除是不支持的
iter.remove();

// 這是正確的做法
iter.next();
iter.remove();
iter.next();
iter.remove();

ArrayList還有兩個(gè)獲取迭代器的方法:listIterator()和listIterator(int),這兩個(gè)方法返還的都是ArrayList$ListItr類型的迭代器

public ListIterator<E> listIterator() {
    return new ListItr(0);
}

public ListIterator<E> listIterator(int index) {
    if (index < 0 || index > size)
        throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }

而ArrayList$ListItr類同樣也是ArrayList的私有內(nèi)部類

private class ListItr extends Itr implements ListIterator<E> {
    // 省略了屬性和方法……
}

ListItr繼承自Itr,是Itr的擴(kuò)展,實(shí)現(xiàn)了從后往前遍歷、添加元素、修改元素、返還索引等方法,其思路大致與Itr相同,因此不在此詳細(xì)分析了

其它方法

ArrayList還有幾個(gè)常用且有效的方法值得分析

  • 修改指定位置元素的值得方法
public E set(int index, E element) {
    rangeCheck(index);
    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

該方法修改指定位置元素的值,并把修改前的值返回。注意,修改方法并沒(méi)有modCount++的操作,因?yàn)樾薷募蟽?nèi)某一元素的值不會(huì)對(duì)集合的長(zhǎng)度發(fā)生影響,也就影響不到迭代器的操作了

  • 清理集合內(nèi)剩余空間的方法
public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size);
    }
}

有時(shí)候,我們確定集合內(nèi)的元素不會(huì)再發(fā)生變化,而集合還有剩余容量時(shí)可以調(diào)用這個(gè)方法來(lái)清理剩余容量。分為兩種情況:

  1. 當(dāng)集合的尺寸為0的時(shí)候,elementData指向常量** EMPTY_ELEMENTDATA**
  2. 當(dāng)集合的尺寸不為0的時(shí)候,根據(jù)當(dāng)前尺寸創(chuàng)建一個(gè)新的數(shù)組,復(fù)制原數(shù)組數(shù)據(jù),將新的數(shù)組賦值給elementData

注意,這也是一個(gè)可能會(huì)影響集合長(zhǎng)度的方法 ,所以也有modCount++操作

  • 手動(dòng)擴(kuò)容的方法
public void ensureCapacity(int minCapacity) {
    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY;
    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
}

有些時(shí)候我們會(huì)在集合實(shí)例化之后才確認(rèn)到具體的容量,而按照默認(rèn)的擴(kuò)容方式(每次擴(kuò)容50%),可能需要多次擴(kuò)容才能達(dá)到預(yù)期的容量。前文說(shuō)過(guò),擴(kuò)容是一個(gè)低效率的操作,為了避免多次執(zhí)行這樣的操作,所以我們可以主動(dòng)調(diào)用ensureCapacity(int)方法來(lái)進(jìn)行擴(kuò)容

參數(shù)minCapacity代表預(yù)期的容量。但是對(duì)于通過(guò)無(wú)參構(gòu)造器創(chuàng)建的ArrayList(也就是說(shuō)其容量為10),如果minCapacity小于10,則ArrayList依然認(rèn)為自己的容量應(yīng)該是10,不會(huì)進(jìn)行任何操作

小結(jié)

本文較為詳細(xì)的分析了ArrayList的源碼,也提出了一些使用ArrayList的技巧,希望能夠?qū)Ω魑婚_(kāi)發(fā)者帶來(lái)幫助。下一步我會(huì)繼續(xù)分享LinkedList的源碼分析,請(qǐng)大家多多支持

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ArrayList 原文見(jiàn):Java 容器源碼分析之 ArrayList 概述 ArrayList是使用頻率最高的...
    Leocat閱讀 276評(píng)論 0 0
  • ArrayList 認(rèn)識(shí) ArrayList是最常見(jiàn)以及每個(gè)Java開(kāi)發(fā)者最熟悉的集合類了 elementData...
    zlb閱讀 224評(píng)論 0 0
  • 定義 除了實(shí)現(xiàn)了List接口,還實(shí)現(xiàn)了RandomAccess,Cloneable, java.io.Serial...
    zhanglbjames閱讀 490評(píng)論 0 0
  • ArrayList 概述 ArrayList 是實(shí)現(xiàn)List接口的動(dòng)態(tài)數(shù)組,每個(gè)ArrayList實(shí)例都有一個(gè)默認(rèn)...
    ZcEDiaos閱讀 279評(píng)論 0 0
  • 果然想念一件事或者一個(gè)人,就很難集中精力去做其他事情。 看看自己好久沒(méi)有做oj ,沒(méi)有上coursera,沒(méi)有靜下...
    robotcator閱讀 199評(píng)論 0 1

友情鏈接更多精彩內(nèi)容