先介紹幾種初始化方法java
// 帶初始化容量的初始化 public ArrayList(int initialCapacity) { if (initialCapacity > 0) { // 初始話一個object 數組 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(); // size是arraylist的長度,賦予集合的長度 if ((size = elementData.length) != 0) { // 長度不爲0, 集合轉化爲數組後,若是類型不是object的,轉爲object if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // 初始化一個空數組 this.elementData = EMPTY_ELEMENTDATA; } }
重點看下c.toArray方法,假如這個集合是個arraylist類型的,那它的toArray實現以下編程
public Object[] toArray() { return Arrays.copyOf(elementData, size); }
發現,調用的是Arrays.copyof方法數組
public static <T> T[] copyOf(T[] original, int newLength) { return (T[]) copyOf(original, newLength, original.getClass()); }
繼續看多線程
/** * * @param original 要複製的數組 * @param newLength 要複製的長度 * @param newType 要複製的數組的class類型 * @param <T> * @param <U> * @return */ public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") // 這步的做用實際上是個優化,假如newType類型是一個object類型,那就直接使用new Object來進行建立數組,加入不是,就用反射的機制建立數組
// 優化的理由應該是:反射建立數組的性能爲比直接建立的性能來的低 // (Object)newType == (Object)Object[].class 這句話就是判斷newType是否是一個object類型 // newType.getComponentType() 實際上是得到數組類型,假如說數組是一個String[],那這能夠拿到String T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); // 調用本地方法,建立數組 System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
再介紹ArrayList兩個操做ide
// 移除全部在c集合裏的元素 public boolean removeAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, false); } // 保留全部在c集合裏的元素 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 { // 根據complement判斷是否保留 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. // 假如出現錯誤,將這個元素後面的全部元素都放到elementData中,不在作去除操做 if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } // 若是沒出現錯誤 if (w != size) { // clear to let GC do its work // 將被去除的元素置爲null for (int i = w; i < size; i++) elementData[i] = null; // 修改次數 modCount += size - w; // 修改當前數組長度 size = w; // 表示作過修改 modified = true; } } return modified; }
提下java的迭代器,經過迭代器來操做ArrayList函數
取得迭代器oop
// 返回帶指定遊標的迭代器ListIterator public ListIterator<E> listIterator(int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index); return new ListItr(index); } // 返回遊標默認爲0的迭代器ListIterator public ListIterator<E> listIterator() { return new ListItr(0); } // 返回默認的迭代器Iterator public Iterator<E> iterator() { return new Itr(); }
再看下迭代器的實現性能
Iterator:優化
private class Itr implements Iterator<E> { int cursor; // 角標,下個元素的位置 int lastRet = -1; // 上次操做的元素位置 int expectedModCount = modCount; //用戶操做ArrayList,會改變modCount public boolean hasNext() { return cursor != size; // 角標不爲ArrayList長度,則表示有下一個 } @SuppressWarnings("unchecked") public E next() { checkForComodification(); // 檢查用戶是否在操做ArrayList,若是操做不在迭代 int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; // 角標位置+1 return (E) elementData[lastRet = i]; // 返回當前元素 } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); // 檢查用戶是否在操做ArrayList,若是操做不在迭代 try { ArrayList.this.remove(lastRet); // ArrayList移除這個元素 cursor = lastRet; lastRet = -1; expectedModCount = modCount; // 從新賦予新的修改次數 } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } // 從當前角標的位置,到結束,consumer爲函數編程接口,傳各個元素進去執行自定義函數,若在操做過程當中,ArrayList發送了修改,則退出迭代,並拋出錯誤 @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(); } // 檢查當前的ArrayList是否被修改 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
listItrui
private class ListItr extends Itr implements ListIterator<E> { // 角標設爲index 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]; } // 設置當前元素的值 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; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } }
能夠看出迭代器在遍歷數組時,同時能夠增長刪除,角標都會隨之發生變化。
而若是用for循環遍歷ArrayList進行添加刪除操做,若是不對當前位置進行一些控制,將發生一些明顯的錯誤。在多線程的狀況,操做ArrayList,你將沒法知曉其它線程是否有進行添加刪除操做,兩方同時操做必將發生錯誤。
咱們能夠看看下面的add操做,它只是作了添加一個元素,並將size+1,而迭代器在添加的時候會進行判斷modcount是否發生改變,並將角標自動+1。保證了操做的正確性。
// 添加 元素
public boolean add(E e) {
// 調整容量
ensureCapacityInternal(size + 1); // Increments modCount!!
// 賦值,並將szie+1
elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { // 記得前面默認初始化ArrayList的時候,會將elementData賦值爲DEFAULTCAPACITY_EMPTY_ELEMENTDATA if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // 這時候判斷當前的size和DEFAULT_CAPACITY,第一次添加,size爲0,因此容量將被初始化爲常量10 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { // 修改次數+1,若是迭代器這時候再操做元素,將拋出異常,並中斷迭代 modCount++; // 若是minCapacity的容量大於數組中元素的長度 if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //newCapacity爲元素長度的1.5倍 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); }
ArrayList中還有個可分割的迭代器
//可分割迭代器 static final class ArrayListSpliterator<E> implements Spliterator<E> { //用於存放ArrayList對象 private final ArrayList<E> list; //起始位置(包含),advance/split操做時會修改 private int index; //結束位置(不包含),-1 表示到最後一個元素 private int fence; //用於存放list的modCount private int expectedModCount; ArrayListSpliterator(ArrayList<E> list, int origin, int fence, int expectedModCount) { this.list = list; this.index = origin; this.fence = fence; this.expectedModCount = expectedModCount; } //獲取結束位置(存在乎義:首次初始化石需對fence和expectedModCount進行賦值) private int getFence() { int hi; ArrayList<E> lst; //fence<0時(第一次初始化時,fence纔會小於0): if ((hi = fence) < 0) { //list 爲 null時,fence=0 if ((lst = list) == null) hi = fence = 0; else { //不然,fence = list的長度。 expectedModCount = lst.modCount; hi = fence = lst.size; } } return hi; } //分割list,返回一個新分割出的spliterator實例 // 這裏要注意,index已被賦值爲mid,起始位置已發生改變 public ArrayListSpliterator<E> trySplit() { //hi爲當前的結束位置 //lo 爲起始位置 //計算中間的位置 int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; //當lo>=mid,表示不能在分割,返回null //當lo<mid時,可分割,切割(lo,mid)出去,同時更新index=mid return (lo >= mid) ? null : new ArrayListSpliterator<E>(list, lo, index = mid, expectedModCount); } //返回true 時,只表示可能還有元素未處理 //返回false 時,沒有剩餘元素處理了。。。 // 注意index+1,角標向前移動了覺得,下次再調用這個方法就是處理下個元素 public boolean tryAdvance(Consumer<? super E> action) { if (action == null) throw new NullPointerException(); //hi爲當前的結束位置 //i 爲起始位置 int hi = getFence(), i = index; //還有剩餘元素未處理時 if (i < hi) { //處理i位置,index+1 index = i + 1; @SuppressWarnings("unchecked") E e = (E)list.elementData[i]; action.accept(e); //遍歷時,結構發生變動,拋錯 if (list.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } return false; } //順序遍歷處理全部剩下的元素 //在這個方法裏,角標index不發生變化,並處理index到fence裏的元素 public void forEachRemaining(Consumer<? super E> action) { int i, hi, mc; // hoist accesses and checks from loop ArrayList<E> lst; Object[] a; if (action == null) throw new NullPointerException(); if ((lst = list) != null && (a = lst.elementData) != null) { //當fence<0時,表示fence和expectedModCount未初始化 if ((hi = fence) < 0) { /// 注意hi在這裏被賦值 mc = lst.modCount; hi = lst.size; } else mc = expectedModCount; if ((i = index) >= 0 && (index = hi) <= a.length) { for (; i < hi; ++i) { @SuppressWarnings("unchecked") E e = (E) a[i]; //調用action.accept處理元素 action.accept(e); } //遍歷時發生結構變動時拋出異常 if (lst.modCount == mc) return; } } throw new ConcurrentModificationException(); } // 返回剩下元素長度 public long estimateSize() { return (long) (getFence() - index); } public int characteristics() { //打上特徵值:、能夠返回size return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; } }
使用下這個ArrayList的可分割迭代器
public static void main(String[] args) throws IOException, ClassNotFoundException { List<String> arrs = new ArrayList<>(); arrs.add("a"); arrs.add("b"); arrs.add("c"); arrs.add("d"); arrs.add("e"); arrs.add("f"); arrs.add("h"); arrs.add("i"); arrs.add("j"); Spliterator<String> a = arrs.spliterator(); //運行到這裏,結果:a:0-9(index-fence) Spliterator<String> b = a.trySplit(); //運行到這裏,結果:a:4-9 b:0-4 Spliterator<String> c = a.trySplit(); //運行到這裏,結果:a:6-9 b:0-4 c:4-6 }
注意,這個分割都是從index到fence,fence通常爲迭代器裏最大操做位置,index爲當前操做的位置,若是操做了第一個元素,好比使用了tryAdvance。那index+1,則分割的時候,也是index到(index+fence)/2;分割出去。
public static void main(String[] args) throws IOException, ClassNotFoundException { List<String> arrs = new ArrayList<>(); arrs.add("a"); arrs.add("b"); arrs.add("c"); arrs.add("d"); arrs.add("e"); arrs.add("f"); arrs.add("h"); arrs.add("i"); arrs.add("j"); Spliterator<String> a = arrs.spliterator(); //運行到這裏,結果:a:0-9(index-fence) Consumer<String> t = (inputStr) -> {System.out.println(inputStr.equals("a") ? "的確爲a":"不是a啊");}; a.tryAdvance(t); //運行到這裏,輸出:的確爲a Spliterator<String> b = a.trySplit(); //運行到這裏,結果:a:5-9 b:1-5 Spliterator<String> c = a.trySplit(); //運行到這裏,結果:a:7-9 b:1-5 c:5-7 }