Java----- ArrayList構造、add、remove、clear方法實現原理原始碼分析
阿新 • • 發佈:2019-01-04
一.ArrayList內部的實現方式
ArrayList內部是通過Object[]實現的。
二.原始碼分析:
(1).構造方法
ArrayList有3個構造方法,先看第一個,array是一個成員變數,它是Object[]型別的,當我們在new一個空參的ArrayList的時候,系統預設呼叫了EmptyArray中的OBJECT屬性,EmptyArray類具體實現如下:public ArrayList() { array = EmptyArray.OBJECT; } public ArrayList(int capacity) { if (capacity < 0) { throw new IllegalArgumentException("capacity < 0: " + capacity); } array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]); } public ArrayList(Collection<? extends E> collection) { if (collection == null) { throw new NullPointerException("collection == null"); } Object[] a = collection.toArray(); if (a.getClass() != Object[].class) { Object[] newArray = new Object[a.length]; System.arraycopy(a, 0, newArray, 0, a.length); a = newArray; } array = a; size = a.length; }
從EmptyArray類中可知,當預設使用ArrayList空參的構造方法的時候,ArrayList內部會new Object[0]的空陣列。再看ArrayList的第二個構造方法,先檢驗引數的有效性,當傳入的引數小於0的時候,會丟擲非法引數異常。如果引數合法,成員變數array的賦值,使用的是一個三元運算,當capacity == 0時,系統預設生成一個空陣列,當capacity>0時,系統會生成一個長度為capacity的陣列。最後看第三個構造方法,第一步對輸入引數的合法性檢驗,若為空,則丟擲空指標異常;第二步將輸入集合轉換成陣列a;第三步判斷當前陣列a是否是Object[]型別,如果不是,建立一個Object型別的陣列進行復制(複製方法使用System.arraycopy),再賦值給a;第四步將轉換的陣列a賦值給成員變數array;第五步將陣列的長度賦值給成員變數size。public final class EmptyArray { private EmptyArray() {} public static final boolean[] BOOLEAN = new boolean[0]; public static final byte[] BYTE = new byte[0]; public static final char[] CHAR = new char[0]; public static final double[] DOUBLE = new double[0]; public static final int[] INT = new int[0]; public static final Class<?>[] CLASS = new Class[0]; public static final Object[] OBJECT = new Object[0];
public static final String[] STRING = new String[0]; public static final Throwable[] THROWABLE = new Throwable[0]; public static final StackTraceElement[] STACK_TRACE_ELEMENT = new StackTraceElement[0]; public static final java.lang.reflect.Type[] TYPE = new java.lang.reflect.Type[0]; public static final java.lang.reflect.TypeVariable[] TYPE_VARIABLE = new java.lang.reflect.TypeVariable[0]; }
(2).add()方法
/**
* Adds the specified object at the end of this {@code ArrayList}.
*
* @param object
* the object to add.
* @return always true
*/
@Override public boolean add(E object) {
Object[] a = array;
int s = size;
if (s == a.length) {
Object[] newArray = new Object[s +
(s < (MIN_CAPACITY_INCREMENT / 2) ?
MIN_CAPACITY_INCREMENT : s >> 1)];
System.arraycopy(a, 0, newArray, 0, s);
array = a = newArray;
}
a[s] = object;
size = s + 1;
modCount++;
return true;
}
這裡只分析簡單的add()方法,第一步將陣列,集合長度賦值給區域性變數a和s;第二步判斷集合的長度是否等於陣列的長度,如果等於,需要重新分配陣列和重新計算分配記憶體的空間大小。原始碼計算記憶體空間的大小,使用的是一個三元表示式,當集合的長度小於 MIN_CAPACITY_INCREMENT/2 時,系統會分配MIN_CAPACITY_INCREMENT各長度;當集合的長度大於 MIN_CAPACITY_INCREMENT/2 時,系統會分配當前長度的一半(s >>1表示當前長度右移一位,相當於s = s/2)。然後將陣列的資料賦值到新的陣列中,再更新原來陣列。private static final int MIN_CAPACITY_INCREMENT = 12;
第三步將傳入的Object物件新增到陣列下標為s處;第四步將當前集合長度加1;第五步modCount自增,它主要是用來記錄集合修改的次數(判斷是否出現併發修改異常)。(3).remove()方法
/**
* Removes the object at the specified location from this list.
*
* @param index
* the index of the object to remove.
* @return the removed object.
* @throws IndexOutOfBoundsException
* when {@code location < 0 || location >= size()}
*/
@Override public E remove(int index) {
/**
* 1.區域性變數賦值
*/
Object[] a = array;
int s = size;
/**
* 2.判斷刪除的下標是否超過了集合的長度,超過丟擲越界異常
*/
if (index >= s) {
throwIndexOutOfBoundsException(index, s);
}
/**
* 3.獲取下標index的所對應的元素
*/
@SuppressWarnings("unchecked")
E result = (E) a[index];
/**
* 4.將下標index後面的所有元素都向前移動一位
*/
System.arraycopy(a, index + 1, a, index, --s - index);
/**
* 5.集合最後一位設定為空,防止記憶體洩露,因為刪除了一個元素
*/
a[s] = null; // Prevent memory leak
/**
* 6.集合長度重新賦值
*/
size = s;
/**
* 7.記錄修改次數
*/
modCount++;
return result;
}
(4).clear()方法
/**
* Removes all elements from this {@code ArrayList}, leaving it empty.
*
* @see #isEmpty
* @see #size
*/
@Override public void clear() {
/**
* 判斷集合大小是否不等於0
*/
if (size != 0) {
/**
* 將陣列的資料元素填充為null
*/
Arrays.fill(array, 0, size, null);
/**
* 集合長度設定為0
*/
size = 0;
/**
* 記錄修改次數
*/
modCount++;
}
}