ArrayList源碼分析(jdk-8)

類及繼承關係

public class ArrayList<E> extends AbstractList<E> 
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable複製代碼

implemnts RandomAccess表明了其擁有隨機快速訪問的能力,能夠根據下標快速訪問元素java

ArrayList底層是數組,會佔據連續的內存空間(數組的長度>真正數據的長度), 數組的缺點:空間效率不高。 

當添加元素,超出現有數組容量時,便會進行擴容操做:

ArrayList的增加因子1,擴容1/2複製代碼
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); }} //如下三個方法實現了Array擴容的操做 private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++;//擴容一定致使此值++ // overflow-conscious code if (minCapacity - elementData.length > 0)//目標長度>現有長途條件下 grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1);//擴容容量爲舊容量的1.5倍,增加因子爲1/2 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);//此方法最總會調用System.ArrayCopy() } public static <T> T[] copyOf(T[] original, int newLength) { return (T[]) copyOf(original, newLength, original.getClass()); } //System類中的靜態方法,這是一個native方法. //經過此方法實現複製出新數組,實現數組的擴容(其是對對象引用的複製-淺度複製) public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)複製代碼

成員變量

int modCount: 每次數組結構改變都會modCount++(增長致使擴容,或者刪)數組

private int size; 集合數據的長度-list.size()獲取的值bash

transient Object[] elementData;真正的存儲東西的元素數組. 長度會>= sizedom

修飾詞:transient,不參與序列化。 通常數組的容量會大於所存元素的個數,因此不必所有參與序列化,浪費多餘空間.在writeObject()中序列化真正存儲數據的元素就能夠了.複製代碼

增,刪,改,查

數組的結構改變標識爲modCount的值改變了ide

System.arraycopy()是一個native的數組之間複製的操做,由集合中的grow(minCapacity) 方法控制函數

👇是ArrayList的增刪改查方法裏,☝兩個關鍵數據的變化的狀況ui

##1.增---public boolean add(E e)

`modCount++
if (minCapacity - elementData.length > 0)`----若是新集合長度>如今數組長度 會`grow(minCapacity)`;複製代碼

##2.刪---remove(Object o)this

`modCount++
grow(minCapacity);`複製代碼

##3. 改---set(int index, E element)spa

兩個操做都沒發生複製代碼

##4.查---contains(Object o) ,indexOf(Object o)code

兩個操做都沒發生複製代碼

迭代器

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;//將modCount的值記錄下來
    public boolean hasNext() {
        return cursor != size;
    }
    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();//每次都會先檢查是否發生過結構改變(modCount值是否相同)
        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();
    }}複製代碼

總結

增,刪,改,查等每次都會先檢查是否索引越界
增刪數組確定會修改modCount的值
System.arrayCopy()發生條件:a集合增長致使擴容,b刪除元素。而集合的改查不會發生數組拷貝
結合安卓加載數據使用場景, 列表展現經常使用,查是高頻操做,增刪較少,因此ArrayList最合適 複製代碼

zyt

相關文章
相關標籤/搜索