/** * Resizable-array implementation of the <tt>List</tt> interface. Implements * all optional list operations, and permits all elements, including * <tt>null</tt>. In addition to implementing the <tt>List</tt> interface, * this class provides methods to manipulate the size of the array that is * used internally to store the list. (This class is roughly equivalent to * <tt>Vector</tt>, except that it is unsynchronized.) 這是一個實現了List接口的可變長度的數組。實現了list接口中的全部方法,容許存放全部的元素,包括null。除了實現list接口,該類還提供了一些方法來操做數組的大小,此數組被用來存儲list的數據。(這個類和vector大體至關,除了它是線程不安全的)
* * <p>The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>, * <tt>iterator</tt>, and <tt>listIterator</tt> operations run in constant * time. The <tt>add</tt> operation runs in <i>amortized constant time</i>, * that is, adding n elements requires O(n) time. All of the other operations * run in linear time (roughly speaking). The constant factor is low compared * to that for the <tt>LinkedList</tt> implementation. * size(),isEmpty(),get(),set()方法使用的一個恆定時間(一個方法具備恆定的執行時間的,也就是代碼不會由於問題規模n的變化而發生變化,時間複雜度記爲O(1))。add操做花費恆定分攤時間,即插入n個元素須要o(n)的時間。 粗略的來講全部其餘操做都以線性時間運行。(即這些操做與元素的個數成線性關係,操做的時間複雜度o(n))。這些操做與LinkedList實現相比,常數因子較低。
* <p>Each <tt>ArrayList</tt> instance has a <i>capacity</i>. The capacity is * the size of the array used to store the elements in the list. It is always * at least as large as the list size. As elements are added to an ArrayList, * its capacity grows automatically. The details of the growth policy are not * specified beyond the fact that adding an element has constant amortized * time cost. * 每一個ArrayList的實例對象都有一個容量(capacity)。這個容量就是這個list中用來存儲元素的數組的大小。它至少和list的大小同樣大。當有元素被增長到集合中時,它的容量會自動增長。除了要求添加一個元素的效率爲「恆定分攤時間」,對於具體實現的細節沒有特別的要求。 * <p>An application can increase the capacity of an <tt>ArrayList</tt> instance * before adding a large number of elements using the <tt>ensureCapacity</tt> * operation. This may reduce the amount of incremental reallocation. 在大批量插入元素前,使用ensureCapacity()方法來增長集合的容量。這或許可以減小擴容增長量的大小。
* <p><strong>Note that this implementation is not synchronized.</strong> * If multiple threads access an <tt>ArrayList</tt> instance concurrently, * and at least one of the threads modifies the list structurally, it * <i>must</i> be synchronized externally. (A structural modification is * any operation that adds or deletes one or more elements, or explicitly * resizes the backing array; merely setting the value of an element is not * a structural modification.) This is typically accomplished by * synchronizing on some object that naturally encapsulates the list. * 注意這個實現類是非同步的。若是有多個線程同時操做一個ArrayList的實例。而後,至少有一個線程修改了list的結構,就必須在外部保證它的線程同步。(結構修改指的是增長或者刪除一個或多個映射;若是僅僅是更改已經存在的 key和value值,不算作結構修改)。這一般須要在一個被封裝好的list對象上,使用同步進行操做。
* If no such object exists, the list should be "wrapped" using the * {@link Collections#synchronizedList Collections.synchronizedList} * method. This is best done at creation time, to prevent accidental * unsynchronized access to the list:<pre> * List list = Collections.synchronizedList(new ArrayList(...));</pre> * 若是沒有這樣的對象存在,那麼就須要使用Collections.synchronizedList方法來包裝這個list對象,並且最好是在建立對象的時候就進行包裝,這是爲了預防對這個list對象進行一些線程不一樣步的操做。舉個例子:List list = Collections.synchronizedList(new ArrayList(...));
* <p><a name="fail-fast"> * The iterators returned by this class's {@link #iterator() iterator} and * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:</a> * if the list is structurally modified at any time after the iterator is * created, in any way except through the iterator's own * {@link ListIterator#remove() remove} or * {@link ListIterator#add(Object) add} methods, the iterator will throw a * {@link ConcurrentModificationException}. Thus, in the face of * concurrent modification, the iterator fails quickly and cleanly, rather * than risking arbitrary, non-deterministic behavior at an undetermined * time in the future. * 該類的集合視圖方法返回的迭代器是fail-fast機制的:在迭代器被建立後,若是list對象被結構化修改後,不管在什麼時候,使用何種方法(除了迭代器自己的remove方法和add方法)來修改它,都會拋出ConcurrentModificationException.所以,面對併發修改操做時,迭代器會迅速且清晰地報錯.而不是冒着在不肯定的時間作不肯定的操做的風險.
* <p>Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the * presence of unsynchronized concurrent modification. Fail-fast iterators * throw {@code ConcurrentModificationException} on a best-effort basis. * Therefore, it would be wrong to write a program that depended on this * exception for its correctness: <i>the fail-fast behavior of iterators * should be used only to detect bugs.</i> 注意,迭代器的fail-fast行爲是不能保證的.通常來講,保證非同步的同步操做是不太可能的.在最優基礎上,Fail-fast迭代器會拋出ConcurrentModificationException.所以,寫一個爲了自身正確性而依賴於這個異常的程序是不對的.迭代器的fail-fast行爲應該只是用來檢測bug而已.
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
繼承的類
AbstractList:抽象類,只需知道此類是List接口的簡單通用實現數組
實現的接口
List:很少說了
RandomAccess:(標記接口)表明支持隨機訪問
Cloneable:(標記接口)表明 Object.clone() 方法能夠合法地對該類實例進行按字段複製。(沒有實現 Cloneable 接口的實例上調用 Object 的 clone 方法,則會致使拋出 CloneNotSupportedException 異常)
java.io.Serializable(標記接口)安全
protected transient int modCount = 0;
/** * Default initial capacity. * 初始默認容量 爲 10 */ private static final int DEFAULT_CAPACITY = 10;
/** * Shared empty array instance used for empty instances. * * 指定該ArrayList容量爲0時,返回該空數組。 */ private static final Object[] EMPTY_ELEMENTDATA = {};
/** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. * * 用於默認大小的空實例的共享空數組實例。 * 這個空數組的實例用來給無參構造使用。當調用無參構造方法,返回的是該數組。 * 將此與EMPTY_ELEMENTDATA區分開來,以便了解在添加第一個元素時要增長多少容量。 */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. * * 存儲ArrayList元素的數組緩衝區 * ArrayList的容量(capacity)就是是此數組緩衝區的長度。 * 聲明爲transient 不會被序列化 * 非私有 是爲了方便內部類調用 */ transient Object[] elementData; // non-private to simplify nested class access
/** * The size of the ArrayList (the number of elements it contains). * * List中元素的個數 */ private int size;
這裏提一點:前面提到size()方法時間複雜度爲O(1),是由於它將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); } }
無參構造,建立一個初始容量爲10 的空序列 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
遵循集合的約定 提供 一個可將Collection轉換爲ArrayList的構造器 這些元素是按照該 Collection 的迭代器返回它們的順序排列的。 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; } }
/** * 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. * * 將ArrayList的容量設置爲當前size的大小,應用可使用此方法最小化實例的存儲空間 * */ public void trimToSize() { modCount++; if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }
/** * Increases the capacity of this <tt>ArrayList</tt> instance, if * necessary, to ensure that it can hold at least the number of elements * specified by the minimum capacity argument. * * 若有必要,增長此ArrayList實例的容量,以確保它至少能夠容納由minCapacity參數指定的元 * 素數。 * * @param minCapacity the desired minimum capacity */ 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 ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); }
ensureCapacityInternal方法,數組容量檢查,不夠時則進行擴容,只供類內部使用,例如add(),addAll()等方法時會調用此方法進行容量檢驗,此時minCapacity 一般爲size+napp
private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code // 只有最小容量比當前容量大時纔會進行擴容 if (minCapacity - elementData.length > 0) grow(minCapacity); } /** * 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; // 先預先擴容1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) // 主要判斷 預期最小容量 minCapacity 是否大於 MAX_ARRAY_SIZE 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; }
總結:dom
public boolean contains(Object o) { // 借用indexOf的方法看是否存在 return indexOf(o) >= 0; } // 實質就是遍歷數組,使用Object的equals方法,返回-1爲不存在此元素,lastIndexOf()方法就是反向遍歷 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; } public boolean add(E e) { // 檢驗是否須要擴容 ensureCapacityInternal(size + 1); // Increments modCount!! // 先在index=size的位置賦值e,再將ArrayList的size增長一位 elementData[size++] = e; return true; } /** * Inserts the specified element at the specified position in this * list. Shifts the element currently at that position (if any) and * any subsequent elements to the right (adds one to their indices). * * @param index index at which the specified element is to be inserted * @param element element to be inserted * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
總結:ide
/** * Removes the element at the specified position in this list. * Shifts any subsequent elements to the left (subtracts one from their * indices). * * @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); // 將數組最後一位 置 null,等待垃圾回收機制來回收 elementData[--size] = null; // clear to let GC do its work return oldValue; } public List<E> subList(int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); return new SubList(this, 0, fromIndex, toIndex); } private class SubList extends AbstractList<E> implements RandomAccess {
ArrayList中的迭代器實現對AbstractList中的迭代器進行了優化源碼分析
/** * Returns an iterator over the elements in this list in proper sequence. * * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>. * * 按原有list的順序返回一個迭代器,遵循fail-fast機制。 * * * @return an iterator over the elements in this list in proper sequence */ public Iterator<E> iterator() { return new Itr(); } /** * An optimized version of AbstractList.Itr */ private class Itr implements Iterator<E> { // 後遊標:指向下一個元素,等於下一個元素的索引值 int cursor; // index of next element to return // 前遊標:指向當前元素,等於當前元素索引值,-1表明在最開始,還未指向元素 int lastRet = -1; // index of last element returned; -1 if no such // 將預期修改次數 和 實際修改次數 保持相等 int expectedModCount = modCount; // 是否有下一個元素 public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") 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 = i + 1; // 後遊標右移 return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { // 調用ArrayList的remove ArrayList.this.remove(lastRet); // remove以後 後遊標左移 cursor = lastRet; // 重製前遊標 lastRet = -1; // 而且會使預期修改次數 和 實際修改次數 保持相等 expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } // 檢查 實際修改次數 和 預期修改次數是否相等 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
/** * Returns a list iterator over the elements in this list (in proper * sequence), starting at the specified position in the list. * The specified index indicates the first element that would be * returned by an initial call to {@link ListIterator#next next}. * An initial call to {@link ListIterator#previous previous} would * return the element with the specified index minus one. * * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>. * * @throws IndexOutOfBoundsException {@inheritDoc} */ public ListIterator<E> listIterator(int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index); return new ListItr(index); } /** * Returns a list iterator over the elements in this list (in proper * sequence). * * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>. * * @see #listIterator(int) */ public ListIterator<E> listIterator() { return new ListItr(0); } /** * An optimized version of AbstractList.ListItr */ private class ListItr extends Itr implements ListIterator<E> { ListItr(int index) { super(); cursor = index; } public boolean hasPrevious() { return cursor != 0; } public int nextIndex() { return cursor; } public int previousIndex() { return cursor - 1; } @SuppressWarnings("unchecked") public E previous() { checkForComodification(); int i = cursor - 1; if (i < 0) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i; return (E) elementData[lastRet = i]; } checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; // 後遊標右移 return (E) elementData[lastRet = i]; public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.set(lastRet, e); } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } public void add(E e) { checkForComodification(); try { int i = cursor; // 在當前元素的後面加入此元素 ArrayList.this.add(i, e); cursor = i + 1; lastRet = -1; // add 操做會致使 modCount++,因此這邊要保持相等 expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } }
remove和add操做成功後 lastRet都會從新賦值爲-1,而且會執行expectedModCount = modCount操做,以防ConcurrentModificationException;優化
ListItr繼承於Itr,增長了previous()等一些方法,最大不一樣是遊標cursor能夠向前移動了。
注意:執行過next()方法後再執行previous(),當前元素並無改變(lastRet沒有變),只是cursor進行了了改變,不要進行常規思考 previous()操做就是當前元素向前移動,next()就是當前元素向後移動,準確來講是cursor進行先後移動,進行previous()操做時 lastRet始終等於cursor,next()操做時cursor始終比lastRet大1
源碼版本爲JDK1.8,只是對平常使用的基本操做的源碼進行了分析,對於1.8的新特性並無涉及,等將主要集合類源碼分析完後,會專門出一篇分析一下1.8中集合的新特性; 有建議或着問題的,請在文末留言,本人水平有限,有錯誤或理解誤差,還請各位多多指導和見諒,如若轉載,請代表出處;