構造函數:有3個構造函數
1)在jdk源碼中ArrayList無參的構造函數,默認初始化大小是10;
2)帶有指定大小參數的構造函數
3)帶有集合參數的構造函數
一、確定ArrarList的容量
1、若ArrayList的容量不足以容納當前的全部元素,設置新的容量 = (原始容量 * 3) / 2 + 1。
2、如果擴容後容量還是不夠,則直接將minCapacity設置爲當前容量。
public void ensureCapacity(int minCapacity) {
// 將“修改統計數”+1,該變量主要是用來實現fail-fast機制的
modCount++;
int oldCapacity = elementData.length;
// 若當前容量不足以容納當前的元素個數,設置新的容量=“(原始容量x3)/2 + 1”
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
//如果還不夠,則直接將minCapacity設置爲當前容量
if (newCapacity < minCapacity)
newCapacity = minCapacity;
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
二、添加元素
public boolean add(E e) {
ensureCapacity(size + 1); // 確定ArrayList的容量大小
elementData[size++] = e; // 添加e到ArrayList中
return true;
}
將Element添加到ArrayList的指定位置
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
ensureCapacity(size+1); //確定ArrarList的容量
//將index位置及後面的元素都往後移一位
System.arraycopy(elementData, index, elementData, index + 1, size - index);
elementData[index] = element; //將e添加到index位置
size++;
}
三、獲取index位置的元素值
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
四、設置index位置的值爲element
public E set(int index, E element) {
RangeCheck(index);
E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
}
五、刪除ArrayList指定位置的元素
public E remove(int index) {
RangeCheck(index); //檢查索引index是否合理
modCount++;
E oldValue = (E) elementData[index]; //保存要刪除位置的元素
int numMoved = size - index - 1; //得到要移動的元素的個數
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index, numMoved);
elementData[--size] = null; //因爲都往後移了一位,所以最後一個元素要置空
return oldValue;
}
刪除元素
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;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0) //從"index+1"開始,用後面的元素替換前面的元素。
System.arraycopy(elementData, index+1, elementData, index, numMoved);
elementData[--size] = null; //將最後一個元素設爲nul
}
六、ArrayList是否包含Object(o)
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
正向查找,返回元素的索引值
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
}
七、返回ArrayList的Object數組
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
八、將集合c追加到ArrayList中
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray(); //得到集合實際保存元素的數組
int numNew = a.length;
ensureCapacity(size + numNew); //確定添加集合後ArrayList的容量合理
System.arraycopy(a, 0, elementData, size, numNew); //利用System.arraycopy方法將數組拷貝到ArrayList集合的數組中
size += numNew;
return numNew != 0;
}
分析ArrayList源碼比較重要的幾點總結:
1、ArrayList是如何確定容量的—->調用ensureCapacity方法。
2、ArrayList是基於數組的,所以獲取元素和設置元素都是這樣的形式:elementData[index],只需獲取到數組索引就可以了。
3、在ArrayList源碼中,大量使用了System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
src:源數組; srcPos:源數組要複製的起始位置; dest:目的數組; destPos:目的數組放置的起始位置; length:複製的長度。
比如ArrayList的增加、刪除、將集合c追加到ArrayList中這三種操作,都使用了這個方法。
4、Arrays類的靜態方法:copyOf(T[] original, int newLength)
original - 要複製的數組 ; newLength - 要返回的副本的長度 ; newType - 要返回的副本的類型
比如ArrayList的toArray()方法就使用了Arrays.copyOf方法。