【JAVA,ArrayList原始碼】閱讀ArrayList原始碼個人理解
閱讀ArrayList原始碼個人理解
近期閱讀了java.util.ArrayList.java的原始碼
ArrayList介紹
從貼出程式碼不難看出,ArrayList是繼承了AbstractList,並且實現了List,RandomAccess,Cloneable,java.io.Serializable。
ArrayList可以無限延展下去的特點。
ArrayList實現了Serializable介面,使它可以序列化之後持久的“存在”。
註釋:序列化,我很困惑,然後就啪啪去查閱。最終自己的大致理解就是,一個java物件可以通過序列化,轉化成一個序列,位元組序列,包括這個物件的資料、屬性、物件的型別等資訊,然後這個序列化之後的物件可以被持久的儲存在檔案中,可以儲存以及傳輸,之後再對檔案通過反序列化之後例項成物件。
ArrayList屬性分析
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ private static final long serialVersionUID = 8683452581122892189L; /** * Default initial capacity. */ private static final int DEFAULT_CAPACITY = 10; /** * Shared empty array instance used for empty instances. */ private static final Object[] EMPTY_ELEMENTDATA = {}; private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Object[] elementData; private int size; ... ... }
serialVersionUID:這個是序列化的標識,序列化和反序列化會通過這個標識進行校驗。
DEFAULT_CAPACITY:這個是初始化的陣列大小。
EMPTY_ELEMENTDATA:初始化空的示例陣列。
DEFAULTCAPACITY_EMPTY_ELEMENTDATA:初始化的時候利用DEFAULT_CAPACITY來限定例項陣列的長度大小。
elementData:使用transient關鍵字修飾的elementData。它是儲存陣列的變數,對於ArrayList非常重要。
註釋:transient,java關鍵字,其修飾的物件不會進行序列化。
size:記錄ArrayList的大小。
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;
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
ArrayList構造引數:為帶長度大小的,不帶引數的。
/**
* Trims the capacity of this <tt>ArrayList</tt> instance to be the
* list's current size. An application can use this operation to minimize
* the storage of an <tt>ArrayList</tt> instance.
*/
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
trimToSize:這個方法是為了,節省空間的,每次ArrayList擴容的時候到會多出一點點,然後可以使用這方法刪除多餘的空間,這樣就可以節約空間。
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
ensureCapacity:對ArrayList進行擴容。簡而言之,通過定量的擴充ArrayList的長度,避免在add()的時候,多次擴容,減少擴容的時間。
ensureExplicitCapacity:進行擴容的操作。
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
grow:擴容的方法。對elementData進行操作。
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;
}
indexOf:用來判斷是否包含相應的物件,如果沒有就返回-1。
/**
* Checks if the given index is in range. If not, throws an appropriate
* runtime exception. This method does *not* check if the index is
* negative: It is always used immediately prior to an array access,
* which throws an ArrayIndexOutOfBoundsException if index is negative.
*/
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
/**
* A version of rangeCheck used by add and addAll.
*/
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
這裡是幾個異常的輸出,基本就是判斷是否越界。
rangeCheck:主要是對於獲取指定位置的物件,移除指定位置的物件,已經更新指定位置的物件這些操作的檢查。
rangeCheckForAdd:對新增物件,超過ArrayList的容量。
outOfBoundsMsg:我們經常看見的數字越界的錯誤資訊就是這個地方定義丟擲的錯誤。
整個ArrayList的原始碼實現,實際上還是有很多內容的,我只是淺顯理解,然後把自己的理解轉化成可以便於理解的文字,ArrayList在實際的開發中利用是極其廣泛的,深入理解ArrayList的原始碼還是對日常的開發工作是有很多很大好處。
這裡只是介紹了一部分內容,在迭代器這塊沒有任何涉及,如有錯誤請指正,謝謝!我將積極更正。
最後附上ArrayList的原始碼,原始碼來自於開源平臺,這裡只提供下載,不做其他用途。