ArrayList源碼

先介紹幾種初始化方法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
    }
相關文章
相關標籤/搜索