源碼之ArrayList和Vector

父類介紹

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable{}

說明:java

  • 繼承AbstractList,實現List接口,提供了add、remove、indexOf、get等相關方法
  • 實現RandomAccess接口,提供了隨機訪問功能。在ArrayList中,咱們便可以經過元素的序號快速獲取元素對象;這就是快速隨機訪問。RandomAccess接口是一個標記接口,它並未定義方法。其目的是用於指示實現類具備隨機訪問特性,在遍歷時使用下標訪問較迭代器更快
  • 實現Cloneable,提供了克隆方法
  • 實現Serializable,支持序列化

屬性

默認屬性

//數組默認大小10
private static final int DEFAULT_CAPACITY = 10;
//默認數據 空數組
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

其餘屬性

數據

transient Object[] elementData;

這裏用transient修飾,是爲了防止自動序列化。緣由:數組

因爲 ArrayList 是基於動態數組實現的,因此並非全部的空間都被使用。所以使用了 transient 修飾,能夠防止被自動序列化。

因此,ArrayList也自定義了序列化和反序列化方法,只序列化當前存放的數據安全

private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        int expectedModCount = modCount;
        s.defaultWriteObject();
        s.writeInt(size);
        // 這裏只序列化已經有的數據,並非全部空間都序列化
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;
        s.defaultReadObject();
        s.readInt(); 

        if (size > 0) {
            int capacity = calculateCapacity(elementData, size);
            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // 反序列化,讀取數據
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }

大小

private int size;//ArrayList的數組大小

修改次數與快速失敗

//修改次數 父類AbstractList全部
protected transient int modCount = 0;
//指望修改次數 父類AbstractList的內部類Itr全部
int expectedModCount = modCount;

說明多線程

ArrayList的全部關於結構變化的操做(add、remove、addAll、removeRange和clear),都會讓modCount++

而在私有內部類迭代器Itr中定義了變量expectedModCount和checkForComodification方法
private class Itr implements Iterator<E> {
    //指望的修改次數
    int expectedModCount = modCount;
    //修改檢查方法()
    final void checkForComodification() {
        //若是修改數和指望修改數不一致,拋出異常
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

好處:快速失敗dom

若是在多線程環境中,使用迭代器操做ArrayList的時候可能形成修改次數不一致,每次迭代器更新數據前檢查,來保證數據安全和一致,若是不一致能讓迭代快速失敗

添加元素

add(obj) 在數組尾部添加

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 擴容(若是必要),而且 modCount++
        elementData[size++] = e;//數組尾部添加元素
        return true;
    }

add(index, obj) 複製數組,效率不好

//在指定位置添加元素
public void add(int index, E element) {
    rangeCheckForAdd(index);//校驗index是否大於數組長度或者小於0

    ensureCapacityInternal(size + 1);  // 擴容(若是必要),而且 modCount++
    //對數據進行復制,目的是把 index 位置空出來放本次插入的數據,並將後面的數據向後移動一個位置
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;//將插入的值放到指定位置index
    size++;//將 size + 1 
}

添加集合 addAll(),效率較差

public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);
		//數組複製和移動
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

修改元素 set

在指定位置設置新的值,並返回舊值this

public E set(int index, E element) {
    rangeCheck(index);//檢查index是否超過數組大小

    E oldValue = elementData(index);//獲取到以前的值
    elementData[index] = element;//設置新值
    return oldValue;//返回以前的值
}

擴容

//擴容檢測
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // 當數組容量不足,調用grow進行擴容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
//擴容
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;//獲取當前容量大小
    int newCapacity = oldCapacity + (oldCapacity >> 1);//新容量=當前容量的1.5倍
    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);
}

快速隨機訪問 get

public E get(int index) {
    rangeCheck(index);//檢查index是否超過數組大小
    return elementData(index);//返回數組指定位置的元素
}

移除元素 remove 效率較差

給定位置移除

移除指定位置元素,返回被移除位置上的元素值線程

public E remove(int index) {
    rangeCheck(index);//index合法檢查
    modCount++;//修改次數++
    E oldValue = elementData(index);//獲取舊值
    int numMoved = size - index - 1;//計算該位置後面的數組大小
    if (numMoved > 0)
        //從新移動數組
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; //清除數組,讓gc收集
    return oldValue;
}

給定元素值移除

public boolean remove(Object o) {
        if (o == null) {//移除null值
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {//移除非null值
            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
    }

Vector

線程安全code

Vector相似於ArrayList,是一個動態數組,只是它是一個線程安全的數組容器。它的add、set、remove方法都是用synchronized來修飾的。

擴容對象

//Vector的擴容,不是按1.5倍,二是1倍
private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        //按原來的1倍擴容
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
相關文章
相關標籤/搜索