ArrayList是JDK中的一個基於數組實現的線性的可變長度的集合類,而且實現了List接口。數組
//建立ArrayList
ArrayList list = new ArrayList();
複製代碼
建立完成後,點擊進入ArrayList源碼,能夠發現是bash
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
複製代碼
這樣的一個無參構造方法對ArrayList
進行了初始化操做,其中elementData
是一個Object
類型的數組,DEFAULTCAPACITY_EMPTY_ELEMENTDATA
也是一個Object
類型的數組且長度爲0。函數
//建立ArrayList
ArrayList list = new ArrayList(20);
複製代碼
再次點擊就會發現會調用一個制定了初始化容量的構造方法ui
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);
}
}
複製代碼
根據代碼可知,咱們傳入參數後會建立一個容量爲20
的數組。若是傳入的不是20
而是0
的話,就會建立一個容量爲空的數組,也就是this.elementData = {}
。this
//建立ArrayList
ArrayList list = new ArrayList();
list.add("aaa");
複製代碼
點擊進入以後能夠發現以下代碼spa
public boolean add(E e) {
//用於檢測容量是否夠用
ensureCapacityInternal(size + 1); // Increments modCount!!
//將元素添加進集合中,而且維護size的值。 size的初始值爲0
elementData[size++] = e;
return true;
}
複製代碼
點擊ensureCapacityInternal(size + 1);
會發現以下代碼code
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
複製代碼
從代碼中能夠看出傳入的是添加元素須要的最小空間,而後再點擊calculateCapacity
方法對象
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//DEFAULT_CAPACITY = 10
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
複製代碼
發現傳入的是一個Object
類型的數組和須要的最小容量。由於elementData
是空的,因此會進入第一個if
判斷,這樣會從10和0
之間選取最大值,結果顯而易見,因此10被返回到ensureExplicitCapacity
的參數列表中。索引
接着再點擊ensureExplicitCapacity
。接口
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
//擴容函數
grow(minCapacity);
}
複製代碼
從這裏能夠看出會將剛纔傳入的10傳到擴容的函數中,再點擊grow
private void grow(int minCapacity) { //minCapacity = 10
//elementData是一個空數組,因此oldCapacity爲0
int oldCapacity = elementData.length;
// newCapacity = 0 + 0 因此newCapacity = 0
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 0 - 10 < 0 true
if (newCapacity - minCapacity < 0)
// newCapacity = 10
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);
}
複製代碼
從中得出newCapacity = 10
,而後調用copyOf
方法進行復制,複製完成就會將elementData
的長度設置爲10。
總結:在第一次調用add()方法時,會將容量初始化爲10,可是若是老是執行添加操做,就會再次到達ArrayList的擴容標準
//建立ArrayList
ArrayList list = new ArrayList();
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa"); //第11次調用add()方法
複製代碼
此時咱們再執行上面的操做,直到這裏
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 11 - 10 > 0 true
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
複製代碼
再次執行擴容操做
private void grow(int minCapacity) { //minCapacity = 11
// oldCapacity = 10
int oldCapacity = elementData.length;
//newCapacity = 10 + 10 / 2 15
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 15 - 11 < 0 false
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 進行copy
elementData = Arrays.copyOf(elementData, newCapacity);
}
複製代碼
當拷貝完成擴容操做執行完畢,elememtData
的容量此時爲15
System.out.println(list.get(2));
複製代碼
get
方法須要傳入數組下標,並經過下標返回數組中的值。點擊get
方法會顯示以下內容
public E get(int index) {
//檢查下標合法性,不合法則拋出異常
rangeCheck(index);
//直接返回數組中下標爲index的元素
return elementData(index);
}
複製代碼
list.set(2, "bbb");
複製代碼
這裏表示想將數組中下標爲2的元素設置爲bbb
。點擊進入
public E set(int index, E element) {
//檢查下標合法性
rangeCheck(index);
//保存索引爲index位置的值
E oldValue = elementData(index);
//將傳入的元素設置在index位置
elementData[index] = element;
//返回保存的元素
return oldValue;
}
複製代碼
經過傳入index和E
類型的元素,更新完成後將原來的元素值返回。
System.out.println(list.remove(2));
複製代碼
刪除下標爲2的元素,並將刪除前的元素返回,點擊remove()方法
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;
}
複製代碼
//建立ArrayList
ArrayList list = new ArrayList();
list.add("aaa");
list.add("bbb");
list.add("ccc");
//建立迭代器
Iterator it = list.iterator();
//判斷迭代器中是否還有下一個元素
while (it.hasNext()){
//將對象取出
Object o = it.next();
System.out.println(o);
}
複製代碼
迭代器能夠遍歷ArrayList
中的元素,點擊iterator()
public Iterator<E> iterator() {
return new Itr();
}
複製代碼
在迭代器內部建立了一個Itr
對象,再點擊
//指向元素的遊標,當前cursor = 0
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
//迭代器中是否包含下一個元素
public boolean hasNext() {
return cursor != size;
}
//將遊標向後移動
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向後移動
cursor = i + 1;
return (E) elementData[lastRet = i];
}
複製代碼
進入以後關注以上方法及參數 由於上面添加了3個元素,因此size
爲3,cursor
與size
不相等,返回true
,因此會進入while
循環並執行next
方法,首先會將cursor
賦值給i,此時i爲0,而後cursor向後移動最後將下標爲0的元素返回。一直循環下去直至hasNext
返回false
。