JDK版本: openJDK 1.8
問題
在ArrayList中,size跟capacity是一樣的東西嗎?
實驗
在ArrayList中有這麼一個構造函數可以讓我們指定初始的容量(Capacity)。
public ArrayList(int initialCapacity);
然後我們可以利用這個構造函數來創建一個ArrayList並在構造函數裏指定初始容量爲10。接着嘗試在下標爲9的位置插入一個數據。
ArrayList list = new ArrayList<Integer>(10);
int index = 9;
int data = 0;
list.add(index, data);
原本我的想法是,既然我們的初始容量可以容納10個數據,那麼在下標爲9的位置插入一個數據應該是沒有問題的。然而程序卻拋出了一個異常錯誤:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 9, Size: 0
根據這個異常錯誤信息,往下標9的位置插入數據超越了數組的界限。
追根究底
這就很奇怪了,明明我們ArrayList的Capacity是10,爲什麼下標9會越界呢?
查看ArrayList的構造函數
爲了尋找原因,我打開了ArrayList的源代碼,首先我們來看一下在ArrayList中可以指定Capacity的構造函數:
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
// 我們傳入的參數爲10,因此 ArrayList 會初始化一個大小爲 10 的 Object 數組
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
由於我們傳入的initialCapacity參數爲10,因此ArrayList會初始化一個大小爲10的 Object 數組來儲存我們的數據。
到此爲止看上去都很合理,ArrayList的底層數組實際上是足夠大到可以讓我們往下標9的位置插入數據,那麼問題會是出在哪裏呢?
查看ArrayList的add(index, data)函數
我們的下一步就是要查看ArrayList中可以往指定下標位置插入數據的add(index, data)函數。
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++;
}
從源代碼中,我們發現有一個函數看起來很可疑:rangeCheckForAdd(index)
根據名字來看似乎是在確認數組是否越界。ctrl + 左鍵 點擊該函數查看源代碼:
private void rangeCheckForAdd(int index) {
// 原來是根據 size 來判斷數組是否越界
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
從代碼中可以看出,ArrayList是使用size屬性來確定數組是否越界,並非capacity。
那麼size屬性是從哪裏來的呢?
如果我們再看回add(index, data)函數,就會發現ArrayList在add操作的最後做了size++的操作。
讓我們再來看看add(E e)函數的源代碼:
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e; // 在末尾插入數據之後,size++
return true;
}
可以看到,add(E e)函數會在數組的末尾插入數據,並進行size++的操作。
也就是說,只有當插入新數據的時候,size纔會往上提升。
同樣的,如果我們檢查 remove(int index) 的源代碼,也會發現它會進行size–的操作。
因此,size表示的是數組中元素的數量,並非數組的容量。
總結
在檢查了ArrayList的源代碼之後,我們可以總結出以下結論:
- 在ArrayList中,size與capacity是不同的概念
- size指的是ArrayList中元素的數量
- capacity指的是在ArrayList底層實現中Object數組的大小,也可以理解爲ArrayList的容量
- ArrayList是使用size來判斷數組是否越界
總結圖
這張總結圖大家可以收藏一下,用作複習。
如果大家覺得文章有用的話,請幫忙點個贊,謝謝!