源碼分析以JDK1.8爲例.html
ArrayList就是動態數組,就是Array的複雜版本.它提供了動態的增長和減小元素,實現了Collection和List接口,靈活的設置數組的大小等好處.UML圖以下:java
源碼解讀
公共屬性
//默認容量 private static final int DEFAULT_CAPACITY = 10; // 空數據 private static final Object[] EMPTY_ELEMENTDATA = {}; //默認容量空數組 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //保存數據的數組 transient Object[] elementData; //元素個數 private int size; //最大數組長度 //一些虛擬機會在數組頭部保存頭信息,佔用更多空間,致使OOM private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
無參構造器
//初始化一個空數組 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
int 構造器
指定初始容量,大於0直接初始化;等於0初始化一個空數組,小於0拋出異常。算法
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); } }
集合構造器
集合參數轉化爲對象數組賦值給元素集合,若是有元素判斷集合類型,若是不是Object[] 執行集合複製轉化爲Object[]. 沒有元素直接返回空集合.數組
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 { //初始化爲空集合 this.elementData = EMPTY_ELEMENTDATA; } }
有一個註釋,c.toArray 可能不會返回Object[].讓參考bug編號6260652.到oracle 官網查看bug https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6260652安全
大意就是Arrays.asList 建立集合,再調用toArray返回的對象不是Object[]類型。測試一下看看:oracle
public void test(){ List<Integer> obj = new ArrayList<>(); obj.add(32); obj.add(344); List<Integer> ls = new ArrayList<>(obj); System.out.println(ls.size()); Object[] c = obj.toArray(); System.out.println(c.getClass()); System.out.println(Object[].class); //Arrays.asList建立 List<Integer> d = Arrays.asList(3,2,3); System.out.println(d.toArray().getClass()); }
2 class [Ljava.lang.Object; class [Ljava.lang.Object; class [Ljava.lang.Integer;
可見Arrays.asList 返回的是Integer[],並不是Object[]. 查看Arrays相關源碼dom
//初始化ArrayList @SafeVarargs @SuppressWarnings("varargs") public static <T> List<T> asList(T... a) { return new ArrayList<>(a); }
此處的ArrayList爲Arrays的內部類.jvm
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L; //泛型數組 private final E[] a; //初始化 ArrayList(E[] array) { a = Objects.requireNonNull(array); } @Override public int size() { return a.length; } //調用a的clone方法 @Override public Object[] toArray() { return a.clone(); } @Override @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { int size = size(); if (a.length < size) return Arrays.copyOf(this.a, size, (Class<? extends T[]>) a.getClass()); System.arraycopy(this.a, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } }
官方顯示,JDK9已經解決。 擴展一下,查看數組的clone方法,length屬性的實現.ide
public void test(){ int [] a = {1,2,3}; System.out.println(a.length); } public static void test2(){ Integer[] f = {3,4}; f.clone(); }
查看byte code源碼分析
public class com.xwolf.ArrayListTest { public com.xwolf.ArrayListTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public void test(); Code: 0: iconst_3 1: newarray int 3: dup 4: iconst_0 5: iconst_1 6: iastore 7: dup 8: iconst_1 9: iconst_2 10: iastore 11: dup 12: iconst_2 13: iconst_3 14: iastore 15: astore_1 16: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 19: aload_1 20: arraylength 21: invokevirtual #3 // Method java/io/PrintStream.println:(I)V 24: return public static void test2(); Code: 0: iconst_2 1: anewarray #4 // class java/lang/Integer 4: dup 5: iconst_0 6: iconst_3 7: invokestatic #5 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 10: aastore 11: dup 12: iconst_1 13: iconst_4 14: invokestatic #5 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 17: aastore 18: astore_0 19: aload_0 20: invokevirtual #6 // Method "[Ljava/lang/Integer;".clone:()Ljava/lang/Object; 23: pop 24: return public static void main(java.lang.String[]); Code: 0: invokestatic #7 // Method test2:()V 3: return }
此處不展開,arraylength、invokevirtual參考官網java虛擬機規範https://docs.oracle.com/javase/specs/jvms/se8/html/index.html.
add方法
//List後追加元素 public boolean add(E e) { //擴容 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(ca lculateCapacity(elementData, minCapacity)); } //計算容量,元素爲空返回默認容量和容量的最大值 private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } //擴容到指定容量,修改次數modCount加1 private void ensureExplicitCapacity(int minCapacity) { //增長修改次數 modCount++; if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { //old容量爲元素數組的元素個數 int oldCapacity = elementData.length; // 擴容至 old + (old/2) int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //超過最大容量值,擴容至Integer的最大值 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); } //大容量,容量值小於0拋出異常,容量值大於最大數組長度返回Integer的最大值2^31-1 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
add(int index, E element)
//指定位置添加元素 public void add(int index, E element) { //邊界檢查 rangeCheckForAdd(index); //擴容 ensureCapacityInternal(size + 1); //將指定位置後的元素複製到擴容後的元素集合中 System.arraycopy(elementData, index, elementData, index + 1, size - index); //指定位置賦值 elementData[index] = element; size++; } //邊界檢查 private void rangeCheckForAdd(int index) { if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } /* @param src the source array. * @param srcPos starting position in the source array. * @param dest the destination array. * @param destPos starting position in the destination data. * @param length the number of array elements to be copied. */ //將src的srcPos的連續length個元素複製到dest的destPos的連續位置(替換) public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
add 集合
public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount //將集合元素追加到elementData後 System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; }
指定位置添加集合
public boolean addAll(int index, Collection<? extends E> c) { //邊界檢查 rangeCheckForAdd(index); Object[] a = c.toArray(); int numNew = a.length; //擴容 ensureCapacityInternal(size + numNew); // Increments modCount //計算要移動的元素數量 int numMoved = size - index; if (numMoved > 0) //先將指定位置後的元素copy移動後指定位置的元素 System.arraycopy(elementData, index, elementData, index + numNew, numMoved); //將空出來的元素用添加的集合參數賦值 System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; }
上圖,更直觀一點:
remove 指定索引位置的元素
public E remove(int index) { //邊界檢查 rangeCheck(index); //增長修改次數 modCount++; //獲取指定索引位置的元素 E oldValue = elementData(index); //須要移動的元素的數量 int numMoved = size - index - 1; if (numMoved > 0) //將index後的元素向前移動一位 System.arraycopy(elementData, index+1, elementData, index, numMoved); //size減1,最後一個元素賦值null,等待GC處理 elementData[--size] = null; // clear to let GC do its work //返回刪除的元素 return oldValue; }
remove指定的元素
//遍歷刪除指定的元素 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) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work }
set
public E set(int index, E element) { //邊界檢查 rangeCheck(index); E oldValue = elementData(index); //賦新值 elementData[index] = element; return oldValue; }
get
public E get(int index) { //邊界檢查 rangeCheck(index); //返回指定索引元素 return elementData(index); }
indexOf
//遍歷獲取第一個元素的索引,找不到返回-1 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; }
contains
//索引大於0即爲包含指定元素 public boolean contains(Object o) { return indexOf(o) >= 0; }
trimToSize
將容量和實際數組元素個數保持一致,刪除擴容的null元素.
public void trimToSize() { modCount++; if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }
retainAll
獲取兩個集合的交集
public boolean retainAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, true); } private boolean batchRemove(Collection<?> c, boolean complement) { final Object[] elementData = this.elementData; int r = 0, w = 0; boolean modified = false; try { for (; r < size; r++) if (c.contains(elementData[r]) == complement) //若是包含元素直接賦值 elementData[w++] = elementData[r]; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. //若是循環異常中斷,正常狀況下r==size if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } //若是w!=size ,將w後的元素賦值爲null if (w != size) { // clear to let GC do its work for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; size = w; modified = true; } } return modified; }
iterator
迭代
public Iterator<E> iterator() { return new Itr(); } private class Itr implements Iterator<E> { int cursor; // index of next element to return 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.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } @Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer<? super E> consumer) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } //檢查修改 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
subList
public List<E> subList(int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); return new SubList(this, 0, fromIndex, toIndex); } //邊界檢查 static void subListRangeCheck(int fromIndex, int toIndex, int size) { if (fromIndex < 0) throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); if (toIndex > size) throw new IndexOutOfBoundsException("toIndex = " + toIndex); if (fromIndex > toIndex) throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); } //內部類 SubList(AbstractList<E> parent, int offset, int fromIndex, int toIndex) { this.parent = parent; this.parentOffset = fromIndex; this.offset = offset + fromIndex; this.size = toIndex - fromIndex; this.modCount = ArrayList.this.modCount; }
sort
只須要知道sort內部是歸併排序和Tim Sort便可.此處不展開詳細的排序算法.
public void sort(Comparator<? super E> c) { final int expectedModCount = modCount; Arrays.sort((E[]) elementData, 0, size, c); if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } modCount++; } public static <T> void sort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c) { if (c == null) { sort(a, fromIndex, toIndex); } else { rangeCheck(a.length, fromIndex, toIndex); if (LegacyMergeSort.userRequested) legacyMergeSort(a, fromIndex, toIndex, c); else TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0); } } // legacyMergeSort private static <T> void legacyMergeSort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c) { T[] aux = copyOfRange(a, fromIndex, toIndex); if (c==null) mergeSort(aux, a, fromIndex, toIndex, -fromIndex); else mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c); } //mergeSort 歸併排序 private static void mergeSort(Object[] src, Object[] dest, int low, int high, int off) { int length = high - low; // Insertion sort on smallest arrays if (length < INSERTIONSORT_THRESHOLD) { for (int i=low; i<high; i++) for (int j=i; j>low && ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--) swap(dest, j, j-1); return; } // Recursively sort halves of dest into src int destLow = low; int destHigh = high; low += off; high += off; int mid = (low + high) >>> 1; mergeSort(dest, src, low, mid, -off); mergeSort(dest, src, mid, high, -off); // If list is already sorted, just copy from src to dest. This is an // optimization that results in faster sorts for nearly ordered lists. if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) { System.arraycopy(src, low, dest, destLow, length); return; } // Merge sorted halves (now in src) into dest for(int i = destLow, p = low, q = mid; i < destHigh; i++) { if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0) dest[i] = src[p++]; else dest[i] = src[q++]; } } ///TimSort.sort static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c, T[] work, int workBase, int workLen) { assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length; int nRemaining = hi - lo; if (nRemaining < 2) return; // Arrays of size 0 and 1 are always sorted // If array is small, do a "mini-TimSort" with no merges if (nRemaining < MIN_MERGE) { int initRunLen = countRunAndMakeAscending(a, lo, hi, c); binarySort(a, lo, hi, lo + initRunLen, c); return; } /** * March over the array once, left to right, finding natural runs, * extending short natural runs to minRun elements, and merging runs * to maintain stack invariant. */ TimSort<T> ts = new TimSort<>(a, c, work, workBase, workLen); int minRun = minRunLength(nRemaining); do { // Identify next run int runLen = countRunAndMakeAscending(a, lo, hi, c); // If run is short, extend to min(minRun, nRemaining) if (runLen < minRun) { int force = nRemaining <= minRun ? nRemaining : minRun; binarySort(a, lo, lo + force, lo + runLen, c); runLen = force; } // Push run onto pending-run stack, and maybe merge ts.pushRun(lo, runLen); ts.mergeCollapse(); // Advance to find next run lo += runLen; nRemaining -= runLen; } while (nRemaining != 0); // Merge all remaining runs to complete sort assert lo == hi; ts.mergeForceCollapse(); assert ts.stackSize == 1; }
總結
- 初始容量爲10
- 動態擴容容量爲 old + old/2
- 隨機查找效率較高
- 插入和刪除慢,須要移動元素
- 排序用歸併排序和TimSort
- 動態刪除元素會拋出異常,可用迭代器實現
- 線程不安全
參考
若有錯誤,歡迎批評指正,望不吝賜教!!!