首先咱們先來看一下ArrayList的全部公共方法。html
注:下面方法除構造函數方法外,其餘方法皆按照字母順序排序。java
1 一、public Arraylist() 2 二、public ArrayList(int initalCapacity) 3 三、public ArrayList(Collection<? extends E> c) 4 四、public boolean add(E e) 5 五、public void add(int index, E element) 6 六、 public boolean addAll(int index, Collection<? extends E> c) 7 七、public boolean addAll(Collection<? extends E> c) 8 八、 public void clear() 9 九、 public Object clone() 10 十、 public boolean contains(Object o) 11 十一、public boolean containsAll(Collection<?> c) 12 十二、public void ensureCapacity(int minCapacity) 13 1三、public boolean equals(Object o) 14 1四、 public void forEach(Consumer<? super E> action) 15 1五、public E get(int index) 16 1六、public int hashCode() 17 1七、 public int indexOf(Object o) 18 1八、public boolean isEmpty() 19 1九、public Iterator<E> iterator() 20 20、public int lastIndexOf(Object o) 21 2一、public ListIterator<E> listIterator() 22 2二、public ListIterator<E> listIterator(int index) 23 2三、public E remove(int index) 24 2四、public boolean remove(Object o) 25 2五、public boolean removeAll(Collection<?> c) 26 2六、public boolean removeIf(Predicate<? super E> filter) 27 2七、 public void replaceAll(UnaryOperator<E> operator) 28 2八、public boolean retainAll(Collection<?> c) 29 2九、public E set(int index, E element) 30 30、public int size() 31 3一、public void sort(Comparator<? super E> c) 32 3二、public Spliterator<E> spliterator() 33 3三、public List<E> subList(int fromIndex, int toIndex) 34 3四、public Object[] toArray() 35 3五、public <T> T[] toArray(T[] a) 36 3六、public String toString() 37 3七、public void trimToSize()
1 //默認容量的大小 2 private static final int DEFAULT_CAPACITY = 10; 3 4 //空數組常量 5 private static final Object[] EMPTY_ELEMENTDATA = {}; 6 7 //默認的空數組常量 8 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; 9 10 //存放元素的數組,從這能夠發現ArrayList的底層實現就是一個Object數組 11 transient Object[] elementData; 12 13 //數組中包含的元素個數 14 private int size; 15 16 //數組的最大上限 17 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
ArrayList一共有三個構造函數,分別爲:算法
1 public ArrayList(int initialCapacity) { 2 if (initialCapacity > 0) { 3 this.elementData = new Object[initialCapacity]; 4 } else if (initialCapacity == 0) { 5 this.elementData = EMPTY_ELEMENTDATA; 6 } else { 7 throw new IllegalArgumentException("Illegal Capacity: "+ 8 initialCapacity); 9 } 10 } 11 public ArrayList() { 12 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; 13 } 14 public ArrayList(Collection<? extends E> c) { 15 elementData = c.toArray(); 16 if ((size = elementData.length) != 0) { 17 // c.toArray might (incorrectly) not return Object[] (see 6260652) 18 if (elementData.getClass() != Object[].class) 19 elementData = Arrays.copyOf(elementData, size, Object[].class); 20 } else { 21 // replace with empty array. 22 this.elementData = EMPTY_ELEMENTDATA; 23 } 24 }
1 public boolean add(E e) { 2 ensureCapacityInternal(size + 1); // Increments modCount!! 3 elementData[size++] = e; 4 return true; 5 } 6 public void add(int index, E element) { 7 rangeCheckForAdd(index); 8 9 ensureCapacityInternal(size + 1); // Increments modCount!! 10 System.arraycopy(elementData, index, elementData, index + 1, 11 size - index); 12 elementData[index] = element; 13 size++; 14 }
add(E e)方法是用來添加一個單個的元素,其調用了私有方法enesureCapacityInternal(size+1).數組
1 private void ensureCapacityInternal(int minCapacity) { 2 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { 3 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); 4 } 5 6 ensureExplicitCapacity(minCapacity); 7 } 8 private void ensureExplicitCapacity(int minCapacity) { 9 modCount++;// 10 // overflow-conscious code 11 if (minCapacity - elementData.length > 0) 12 grow(minCapacity); 13 } 14 private void grow(int minCapacity) { 15 // overflow-conscious code 16 int oldCapacity = elementData.length; 17 int newCapacity = oldCapacity + (oldCapacity >> 1); 18 if (newCapacity - minCapacity < 0) 19 newCapacity = minCapacity; 20 if (newCapacity - MAX_ARRAY_SIZE > 0) 21 newCapacity = hugeCapacity(minCapacity); 22 // minCapacity is usually close to size, so this is a win: 23 elementData = Arrays.copyOf(elementData, newCapacity); 24 }
ArrayList添加多個元素的方法同樣有兩個,分別爲:app
1 public boolean addAll(Collection<? extends E> c) { 2 Object[] a = c.toArray(); 3 int numNew = a.length; 4 ensureCapacityInternal(size + numNew); // Increments modCount 5 System.arraycopy(a, 0, elementData, size, numNew); 6 size += numNew; 7 return numNew != 0; 8 } 9 10 public boolean addAll(int index, Collection<? extends E> c) { 11 rangeCheckForAdd(index); 12 13 Object[] a = c.toArray(); 14 int numNew = a.length; 15 ensureCapacityInternal(size + numNew); // Increments modCount 16 17 int numMoved = size - index; 18 if (numMoved > 0) 19 System.arraycopy(elementData, index, elementData, index + numNew, 20 numMoved); 21 22 System.arraycopy(a, 0, elementData, index, numNew); 23 size += numNew; 24 return numNew != 0; 25 }
插入多個元素,與插入單個元素的邏輯是同樣的,在這裏就再也不重複了。dom
ArrayList刪除元素的方法一共有五個,分別是ide
1 public E remove(int index) { 2 rangeCheck(index); 3 4 modCount++; 5 E oldValue = elementData(index); 6 7 int numMoved = size - index - 1; 8 if (numMoved > 0) 9 System.arraycopy(elementData, index+1, elementData, index, 10 numMoved); 11 elementData[--size] = null; // clear to let GC do its work 12 13 return oldValue; 14 }
remove(int index)的處理邏輯:先檢查index是否大於elementDate的size,若是大於的話,則拋出異常;而後獲取elementDate[index],留在方法結束後返回;而後複製素組,從index+1開始,複製size-index-1個元素,複製到elementDate,從index開始;最後設置elementDate[--size]=null;函數
1 public boolean remove(Object o) { 2 if (o == null) { 3 for (int index = 0; index < size; index++) 4 if (elementData[index] == null) { 5 fastRemove(index); 6 return true; 7 } 8 } else { 9 for (int index = 0; index < size; index++) 10 if (o.equals(elementData[index])) { 11 fastRemove(index); 12 return true; 13 } 14 } 15 return false; 16 }
remove(Object o)的邏輯:先判斷Object 是否爲null,若是爲null,則遍歷ArrayList,刪除全部的null值,若是有值被刪除,則返回true;若是Object不爲null,一樣遍歷ArrayList,刪除ArrayList中相同的元素,若是有元素被刪除,則返回true.post
而fastRemove(int index)的邏輯與remove(int index),徹底一致,只是少了對index的驗證。學習
1 public boolean removeAll(Collection<?> c) { 2 Objects.requireNonNull(c); 3 return batchRemove(c, false); 4 }
1 private boolean batchRemove(Collection<?> c, boolean complement) { 2 final Object[] elementData = this.elementData; 3 int r = 0, w = 0; 4 boolean modified = false; 5 try { 6 for (; r < size; r++) 7 if (c.contains(elementData[r]) == complement) 8 elementData[w++] = elementData[r]; 9 } finally { 10 // Preserve behavioral compatibility with AbstractCollection, 11 // even if c.contains() throws. 12 if (r != size) { 13 System.arraycopy(elementData, r, 14 elementData, w, 15 size - r); 16 w += size - r; 17 } 18 if (w != size) { 19 // clear to let GC do its work 20 for (int i = w; i < size; i++) 21 elementData[i] = null; 22 modCount += size - w; 23 size = w; 24 modified = true; 25 } 26 } 27 return modified; 28 }
從上面的代碼咱們能夠看出,remove(Collection<?> c)的邏輯:先判斷c是否爲null,若是爲null,則拋出異常。而後遍歷elementDate,若是c包含數組elementDate中的元素
,則將該元素添加一次替換原elementDate數組中,最後,將數組的其他位置設爲null,若是新數組比原來數組中的元素少,則已經刪除了元素,返回true.
1 public void clear() { 2 modCount++; 3 4 // clear to let GC do its work 5 for (int i = 0; i < size; i++) 6 elementData[i] = null; 7 8 size = 0; 9 }
clear()方法的邏輯:遍歷,刪除全部元素。
除此以外,還有一個retainAll(collenction<T> c)方法,該方法願意是取得兩個集合得交集,在這裏也能夠理解爲刪除集合中不與collection c 重複得元素。
1 return batchRemove(c, true);
能夠看到,它得處理邏輯和removeAll是一樣得邏輯,這裏就再也不重複了。
在JDK1.8以前,修改元素只有一個方法,就是set(int index,Object c).
1 public E set(int index, E element) { 2 rangeCheck(index); 3 4 E oldValue = elementData(index); 5 elementData[index] = element; 6 return oldValue; 7 }
邏輯很簡單,就是先檢查index,而後新元素替換舊元素,並返回舊元素。
在JDK1.8中,添加了一個新方法,批量修改replaceAll(UnaryOperator<E> operator):
1 public void replaceAll(UnaryOperator<E> operator) { 2 Objects.requireNonNull(operator); 3 final int expectedModCount = modCount; 4 final int size = this.size; 5 for (int i=0; modCount == expectedModCount && i < size; i++) { 6 elementData[i] = operator.apply((E) elementData[i]); 7 } 8 if (modCount != expectedModCount) { 9 throw new ConcurrentModificationException(); 10 } 11 modCount++; 12 }
UnaryOperator<T> extends Function<T, T>,而Function<T,R>方法中有一個抽象方法,R apply<T,t>,方法的原意應該是將一個T轉換成R.而這裏使用,UnaryOperator,則只能將T轉換成T。咱們在使用ReplaceAll方法是,必須重寫apply方法,做爲轉換規則。例如:
1 public class ArrayListTest { 2 public static void main(String[] args) { 3 List<String> list = new ArrayList<String>(); 4 list.add("科比"); 5 list.add("詹姆斯"); 6 list.add("庫裏"); 7 list.replaceAll(new UnaryOperator<String>() { 8 @Override 9 public String apply(String t) { 10 // TODO Auto-generated method stub 11 return t+"牛逼"; 12 } 13 }); 14 System.out.println(list); 15 } 16 }
[科比牛逼, 詹姆斯牛逼, 庫裏牛逼]
1 public E get(int index) { 2 rangeCheck(index); 3 4 return elementData(index); 5 }
get(int index)方法,經過元素的下標來獲取元素。其原理就是獲取數組的當前下表的元素。
1 public int indexOf(Object o) { 2 if (o == null) { 3 for (int i = 0; i < size; i++) 4 if (elementData[i]==null) 5 return i; 6 } else { 7 for (int i = 0; i < size; i++) 8 if (o.equals(elementData[i])) 9 return i; 10 } 11 return -1; 12 }
indextOf(Object o),查找ArrayList是否含有某元素,且返回該元素在集合中的第一個位置的下標。經過遍歷元素,獲取該集合所含有的第一個該元素的下標。若是不含有該元素,則返回-1.
1 public int lastIndexOf(Object o) { 2 if (o == null) { 3 for (int i = size-1; i >= 0; i--) 4 if (elementData[i]==null) 5 return i; 6 } else { 7 for (int i = size-1; i >= 0; i--) 8 if (o.equals(elementData[i])) 9 return i; 10 } 11 return -1; 12 }
lastIndexOf(Object o),與indexOf方法想法,該方法查找該元素在集合中最後一個位置,並返回下標。其邏輯與indexOf基本一致,只不過是在遍歷的時候選擇從後往前遍歷。
1 public boolean isEmpty() { 2 return size == 0; 3 }
isEmpth()方法用來查看集合是否爲空集合。若是size=0,則爲空集合,返回true。不然返回false。
public boolean contains(Object o) { return indexOf(o) >= 0; }
contains(Object o)查看集合中是否含有某元素。其調用indexOf(Object o),若是含有返回ture,不然返回false.
public int size() { return size; }
size()方法用來查看集合中含有多少個元素,返回元素個數。
1 public Object clone() { 2 try { 3 ArrayList<?> v = (ArrayList<?>) super.clone(); 4 v.elementData = Arrays.copyOf(elementData, size); 5 v.modCount = 0; 6 return v; 7 } catch (CloneNotSupportedException e) { 8 // this shouldn't happen, since we are Cloneable 9 throw new InternalError(e); 10 } 11 }
clone()方法,用來複制集合並返回一個新的集合。而查看copyOf源碼,發現最底層是使用native方法進行的複製。我沒法肯定其究竟是深複製仍是淺複製。
private static native Object newArray(Class<?> componentType, int length) throws NegativeArraySizeException;
因此我寫了一個簡單的測試代碼,代碼以下:
1 public class ArrayListTest{ 2 public static void main(String[] args) { 3 ArrayList<User> list = new ArrayList<User>(); 4 list.add(new User("科比")); 5 list.add(new User("詹姆斯")); 6 list.add(new User("庫裏")); 7 ArrayList list1= (ArrayList) list.clone(); 8 User user = list.get(1); 9 user.name = "麥迪"; 10 System.out.println(list1); 11 } 12 } 13 14 class User{ 15 String name; 16 public User(String name){ 17 this.name = name; 18 } 19 @Override 20 public String toString() { 21 return name; 22 } 23 }
打印結果爲:
[科比, 麥迪, 庫裏]
說明ArrayList的複製爲潛複製,由於其數組中的元素,並無進行值複製,而是直接複製了元素的引用。
在Java8中,ArrayList添加了一種新的遍歷方法。foreach+lambda表達式遍歷。代碼以下:
1 public class ArrayListTest{ 2 public static void main(String[] args) { 3 ArrayList<String> list = new ArrayList<String>(); 4 list.add("科比"); 5 list.add("詹姆斯"); 6 list.add("庫裏"); 7 list.forEach((s)->System.out.println(s)); 8 } 9 }
由於不懂lambda表達式的實現原理,foreach的源碼實在看不懂。等之後研究了lambda表達式的實現原理,在回來研究下foreach方法。
在Java8中,ArrayList一樣新添加了一種排序方法。sort(Comparator<? super E> c).源碼以下:
1 @Override 2 @SuppressWarnings("unchecked") 3 public void sort(Comparator<? super E> c) { 4 final int expectedModCount = modCount; 5 Arrays.sort((E[]) elementData, 0, size, c); 6 if (modCount != expectedModCount) { 7 throw new ConcurrentModificationException(); 8 } 9 modCount++; 10 }
發現,ArrayList的排序,其實就是調用了數組的排序。咱們繼續往下看,數組是如何排序的:
1 public static <T> void sort(T[] a, int fromIndex, int toIndex, 2 Comparator<? super T> c) { 3 if (c == null) { 4 sort(a, fromIndex, toIndex); 5 } else { 6 rangeCheck(a.length, fromIndex, toIndex); 7 if (LegacyMergeSort.userRequested) 8 legacyMergeSort(a, fromIndex, toIndex, c); 9 else 10 TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0); 11 } 12 }
1 public static void sort(Object[] a, int fromIndex, int toIndex) { 2 rangeCheck(a.length, fromIndex, toIndex); 3 if (LegacyMergeSort.userRequested) 4 legacyMergeSort(a, fromIndex, toIndex); 5 else 6 ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0); 7 }
1 private static void legacyMergeSort(Object[] a, 2 int fromIndex, int toIndex) { 3 Object[] aux = copyOfRange(a, fromIndex, toIndex); 4 mergeSort(aux, a, fromIndex, toIndex, -fromIndex); 5 }
1 @SuppressWarnings({"unchecked", "rawtypes"}) 2 private static void mergeSort(Object[] src, 3 Object[] dest, 4 int low, 5 int high, 6 int off) { 7 int length = high - low; 8 9 // Insertion sort on smallest arrays 10 if (length < INSERTIONSORT_THRESHOLD) { 11 for (int i=low; i<high; i++) 12 for (int j=i; j>low && 13 ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--) 14 swap(dest, j, j-1); 15 return; 16 } 17 18 // Recursively sort halves of dest into src 19 int destLow = low; 20 int destHigh = high; 21 low += off; 22 high += off; 23 int mid = (low + high) >>> 1; 24 mergeSort(dest, src, low, mid, -off); 25 mergeSort(dest, src, mid, high, -off); 26 27 // If list is already sorted, just copy from src to dest. This is an 28 // optimization that results in faster sorts for nearly ordered lists. 29 if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) { 30 System.arraycopy(src, low, dest, destLow, length); 31 return; 32 } 33 34 // Merge sorted halves (now in src) into dest 35 for(int i = destLow, p = low, q = mid; i < destHigh; i++) { 36 if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0) 37 dest[i] = src[p++]; 38 else 39 dest[i] = src[q++]; 40 } 41 }
1 /** To be removed in a future release. */ 2 private static <T> void legacyMergeSort(T[] a, int fromIndex, int toIndex, 3 Comparator<? super T> c) { 4 T[] aux = copyOfRange(a, fromIndex, toIndex); 5 if (c==null) 6 mergeSort(aux, a, fromIndex, toIndex, -fromIndex); 7 else 8 mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c); 9 }
1 @SuppressWarnings({"rawtypes", "unchecked"}) 2 private static void mergeSort(Object[] src, 3 Object[] dest, 4 int low, int high, int off, 5 Comparator c) { 6 int length = high - low; 7 8 // Insertion sort on smallest arrays 9 if (length < INSERTIONSORT_THRESHOLD) { 10 for (int i=low; i<high; i++) 11 for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--) 12 swap(dest, j, j-1); 13 return; 14 } 15 16 // Recursively sort halves of dest into src 17 int destLow = low; 18 int destHigh = high; 19 low += off; 20 high += off; 21 int mid = (low + high) >>> 1; 22 mergeSort(dest, src, low, mid, -off, c); 23 mergeSort(dest, src, mid, high, -off, c); 24 25 // If list is already sorted, just copy from src to dest. This is an 26 // optimization that results in faster sorts for nearly ordered lists. 27 if (c.compare(src[mid-1], src[mid]) <= 0) { 28 System.arraycopy(src, low, dest, destLow, length); 29 return; 30 } 31 32 // Merge sorted halves (now in src) into dest 33 for(int i = destLow, p = low, q = mid; i < destHigh; i++) { 34 if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0) 35 dest[i] = src[p++]; 36 else 37 dest[i] = src[q++]; 38 } 39 }
能夠看出,當比較器爲空時,調用了mergeSort(Object[] src,Object[] dest,int low, int high, int off)方法,不爲空時,調用了mergeSort(Object[] src,Object[] dest,int low, int high, int off,Comparator c)方法,兩個方法基本如出一轍,惟一的區別就是在有默認比較器的時候,兩個元素的比較實用默認比較器的比較方法來比較。
仔細看兩個方法,能夠看出,ArrayList.sort方法 時間上是使用了一種優化事後的遞歸排序,在數組長度小於7的時候使用直接插入排序。數組長度大於7的時候,使用歸併排序,直至子數組的長度小於7.
歸併排序詳見個人另外一篇隨筆經典排序算法--歸併排序。
寫在最後: