ArrayList的基本原理
在Eclipse中按著ctrl鍵鼠標(biāo)點(diǎn)擊ArrayList驾孔,打開源代碼缚去。
1.new ArrayList()原理
List list = new ArrayList();
List list2 = new ArrayList(10);
源代碼(抽取如下):
package test;
public class ArrayList{
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//定義一個(gè)空數(shù)組
private static final Object[] EMPTY_ELEMENTDATA = {};//定義一個(gè)空數(shù)組
transient Object[] elementData;//定義一個(gè)數(shù)組
//initialCapacity是定義集合的大小
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;
}
}
解釋:首先我們可以看到2個(gè)ArrayList構(gòu)造方法,一個(gè)無(wú)參構(gòu)造器叠艳,一個(gè)有參構(gòu)造器狸剃。
無(wú)參構(gòu)造器:為elementData這個(gè)對(duì)象數(shù)組賦了一個(gè)空值卖宠,也就是建立了一個(gè)空數(shù)組
有參構(gòu)造器:傳入集合大小秉氧,如果大于0,則創(chuàng)建一個(gè)有初始大小的數(shù)組;如果等于0,則創(chuàng)建一個(gè)空數(shù)組蚤假;如果小于0磷仰,則拋出異常箍土。
2.add()背后的原理
list.add(E e);
在ArrayList源文件中瞒爬,使用快捷鍵ctrl+o,找到add(E e)并點(diǎn)擊
源代碼:
private int size;
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
解釋:首先可以看到返回的是boolean值矢空。當(dāng)我們添加一個(gè)元素時(shí)先執(zhí)行ensureCapacityInternal(size + 1),然后執(zhí)行elementData[size] = e燕侠,最后size進(jìn)行自增運(yùn)算七问。這里就是list.size()方法所獲取的返回值,而這個(gè)返回值代表的是集合中添加的元素個(gè)數(shù),而不是集合的大小古程。現(xiàn)在我們來(lái)看第一行代碼所代表的意思:
ensureCapacityInternal(size + 1);
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
解釋:這個(gè)方法傳入了一個(gè)參數(shù)(size+1),就是我們添加的所有元素的個(gè)數(shù)茁裙。此時(shí)如果數(shù)組elementData為空,則選取DEFAULT_CAPACITY和(size+1)中的最大值。那么DEFAULT_CAPACITY又是多少呢谈喳?按下ctrl鍵赏僧,點(diǎn)擊這個(gè)變量,可以看到:
private static final int DEFAULT_CAPACITY = 10;
不錯(cuò),是10。也就是說(shuō)灶搜,如果我們傳入的(size+1),也就是我們添加的元素的總個(gè)數(shù)小于10的話,那么集合會(huì)自動(dòng)將自己的大小設(shè)置為10工窍,但是此時(shí)集合中的元素還是(size+1)個(gè)割卖,相當(dāng)于:
List list = new ArrayList(10);//此時(shí)elementData.length的值為0,而集合大小為10
如果(size+1)大于10的話患雏,就相當(dāng)于:
List list = new ArrayList(size+1);//此時(shí)elementData.length的值為size+1鹏溯,而集合長(zhǎng)度是(size+1)的1.5倍
下面再看一下最后一行代碼:
ensureExplicitCapacity(minCapacity);
源代碼:
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
解釋:首先也是講我們之前獲取的minCapacity這個(gè)參數(shù)傳進(jìn)來(lái)。modCount是我們操作的次數(shù)纵苛,這個(gè)不用管剿涮。看后面攻人,此時(shí)假設(shè)elementData.length的值為1的話,minCapacity為10取试,明顯大于elementData數(shù)組長(zhǎng)度,會(huì)執(zhí)行g(shù)row方法怀吻,下面我們看grow方法:
grow(int)
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
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);
}
解釋:首先依然傳入minCapacity,此時(shí),并創(chuàng)建了一個(gè)變量oldCapacity,其值為數(shù)組長(zhǎng)度1或10瞬浓,并對(duì)其增加自身的一半,賦值給newCapacity蓬坡,如果newCapacity小于傳入的數(shù)猿棉,就將集合大小設(shè)為minCapacity,如果newCapacity大于集合所能存儲(chǔ)的最大值,就將集合大小設(shè)置為最大值屑咳,最后復(fù)制一個(gè)新的數(shù)組萨赁。就實(shí)現(xiàn)了數(shù)組大小的擴(kuò)展。
3.size()背后的原理
list.size()
public int size() {
return size;
}
解釋: 可以看到這里直接返回一個(gè)int類型的size,就是我們剛才的那個(gè)size
注意:
1. 從源碼可以看出兆龙,在第一次向集合中添加元素的時(shí)候杖爽,集合大小就變?yōu)?0了
2. 默認(rèn)長(zhǎng)度擴(kuò)展是自身長(zhǎng)度的50%
3. 以上寫的數(shù)組其實(shí)也是集合,不必糾結(jié)
總結(jié):整體上代碼很多但其實(shí)就完成了2個(gè)功能:
1.通過(guò)add(E e)這個(gè)方法添加元素
2. 通過(guò)以下三個(gè)方法對(duì)集合(數(shù)組)擴(kuò)展
ensureCapacityInternal(int minCapacity)//獲取集合的size
ensureExplicitCapacity(int minCapacity)//判斷size是否超出集合大小
grow(int minCapacity)//擴(kuò)展集合