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è)比較直觀的信息:
- 集合的默認(rèn)容量是10,即調(diào)用無(wú)參構(gòu)造器生成的ArrayList,在不擴(kuò)容的情況下,最多能夠存儲(chǔ)10個(gè)數(shù)據(jù)
- 集合的本質(zhì)是一個(gè)類型為Object的數(shù)組
要有一個(gè)值得注意的地方,成員變量中包含兩個(gè)用于初始化elementData的空數(shù)組:EMPTY_ELEMENTDATA和DEFAULTCAPACITY_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)清理剩余容量。分為兩種情況:
- 當(dāng)集合的尺寸為0的時(shí)候,elementData指向常量** EMPTY_ELEMENTDATA**
- 當(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)大家多多支持