ArrayList多是在開發中使用最多的集合類。ArrayList其實就是一個動態數組,它會根據元素的個數進行動態擴容。java
下面是部分源碼,本次源碼基於jdk1.7:數組
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8683452581122892189L; /** * ArrayList默認初始容量 */ private static final int DEFAULT_CAPACITY = 10; /** * 使用無參構造方法時ArrayList使用的空數組 * Shared empty array instance used for empty instances. */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * ArrayList維護用於存放數據的數組 * */ private transient Object[] elementData; /** * 數組大小 * The size of the ArrayList (the number of elements it contains). * * @serial */ private int size; /** * 構造一個空數組,自定義指定初始容量 * * @param initialCapacity 自定義初始容量 * @throws IllegalArgumentException if the specified initial capacity * is negative */ public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } /** * 構造一個空數組,初始容量是10 */ public ArrayList() { super(); this.elementData = EMPTY_ELEMENTDATA; } /** * Constructs a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); size = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } /** * 私用方法用於保證數組容量,先判斷數組是否爲空,爲空則容量最少爲10 */ private void ensureCapacityInternal(int minCapacity) { if (elementData == EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } /** * 該方法被調用一次modCount內部修改計數器會加1,modCount計數器被定義在父類AbstractList中 * modCount被內部實現Iterator和ListIterator的類使用 * 該方法考慮了溢出,當須要的容量超過了當前數組的容量開始調用grow方法進行擴容 */ private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } /** * 最大可分配容量 */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * 該方法用於增長數組的容量,確保可容納指定的最小長度的元素個數 * 按照數組元容量的1.5倍擴容,這個擴容量主要是綜合考慮了擴容次數和內存使用方便考慮的, * 若是擴容倍數大了浪費內存,小了會增長擴容次數增長開銷。 * 該方法實際是計算好最終的擴容量而後交給Arrays.copyOf->System.arraycopy * Systeam的arraycopy是一個native的方法實現數組的拷貝生成新的數組 * @param minCapacity the desired minimum capacity */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //等價於int newCapacity = oldCapacity + oldCapacity/2,即按照當前容量的1.5倍擴容; int newCapacity = oldCapacity + (oldCapacity >> 1); //若是原數組1.5倍容量小於指定的最小容量,則使用指定的最小容量 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //若是原數組1.5倍容量大於MAX_ARRAY_SIZE(ps:Integer.MAX_VALUE - 8),則使用MAX_ARRAY_SIZE作容量 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); } /** * 確保最大容量不能超過MAX_ARRAY_SIZE,超過了直接強制使用MAX_ARRAY_SIZE做爲容量 */ private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } /** * * 添加指定的元素,添加元素前調用ensureCapacityInternal方法來保證容量正常 * 固然每增長一個元素modCount會加1 * @param e element to be appended to this list * @return <tt>true</tt> (as specified by {@link Collection#add}) */ public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } /** * 它也增長了modCount,而後計算要移動的元素個數,從index日後的元素都往前移動一位, * 實際調用System.arraycopy方法移動元素。elementData[--size] = null; * 這行代碼將size減一,同時將最後一個位置設爲null方便被回收 * * @param index the index of the element to be removed * @return the element that was removed from the list * @throws IndexOutOfBoundsException {@inheritDoc} */ 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; } }