java提供的list

ArrayList

其內部使用Object[]數組來存儲,默認長度爲10,一次增長爲原長度的1.5倍,當1.5倍超過int的最大值時爲int的最大值,再大一點就報錯OOM
ArrayList在add元素時,先檢測容量是否夠add,不夠就擴容1.5倍,然後將元素加入數組中,長度+1,這裏爲做多線程的併發處理,在多線程進行添加時,可能出現一起擴容,或同時將元素加到一個位置上,導致異常或數據丟失.

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 判斷容量夠不夠用,不夠就擴容
        elementData[size++] = e;//添加元素,長度加一
        return true;
    }

private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//是不是空數組
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//是不是比原始的10要小
        }

        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);//這裏的oldCapacity >> 1就是原長度除以2,即擴容爲原來長度的1.5倍
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);//檢查是否大於最大值,這裏可能會拋出oom
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);//將數組複製到新的數組中
    }

CopyOnWriteArrayList

寫時複製,在add數據時,會有加鎖處理,再進行先複製原數組,在對新數組進行添加操作,最後在指向新數組,以此保證最終的一致性,但其不能保證數據讀取的實時性,因爲在寫入時需要更多的時間了.

public boolean add(E e) {
        synchronized (lock) {//加鎖,此處有些版本使用ReentrantLock鎖
            Object[] elements = getArray();//獲取原數組
            int len = elements.length;//原數組長度
            Object[] newElements = Arrays.copyOf(elements, len + 1);//複製原數組且長度+1
            newElements[len] = e;//新數組加入元素
            setArray(newElements);//指向新的數組,即替換原數組
            return true;
        }
    }

由此可見,寫時複製列表的數組擴容每次擴容長度爲+1,使用鎖的機制來保證同一時刻只有一個在寫,從而保證數組最終的一致性,且能保證在寫的時候,原數據依然可以讀取,但其讀取的是舊數據.
當然由於複製數組,會造成更多的內存佔用,可能導致gc頻繁會gc時間較長,所以使用與讀多寫少的地方

Vector

向量列表,與ArrayList類似,在初始化的時候可設置其初始大小,默認爲10,但每次擴容的長度可在初始化時設置,若不設置,默認增長爲原數組的兩倍.除此之外,Vector中的方法都進行了同步操作,一次解決多線程的併發問題,但由於都進行了同步,所以效率會比其他的列表低.

public synchronized boolean add(E var1) {//整個方法都同步
        ++this.modCount;
        this.ensureCapacityHelper(this.elementCount + 1);//擴容判斷
        this.elementData[this.elementCount++] = var1;//存入元素
        return true;
    }
public synchronized E get(int var1) {//讀的時候也是整個方法都同步
        if(var1 >= this.elementCount) {//越界直接拋異常
            throw new ArrayIndexOutOfBoundsException(var1);
        } else {
            return this.elementData(var1);
        }
    }

Stack

繼承與Vector的棧,其中的方法也是同步的,符合棧數據結構的先進後出,使用push()入棧,pop()出棧,peek()獲取棧頂元素但不出棧,search()搜索對應數據在棧中的位置,empty()判斷是否0元素

IdentityStack

與Stack一樣,但其不同之處在於相等的判斷,Stack相等的判斷使用equls(),而IdentityStack使用==,即IdentityStack爲對象相等,Stack爲值相等
IdentityStack中爲:

public synchronized int indexOf(Object o, int pos) {
        for (int i = pos; i < size(); i++) {
            if (get(i) == o) {//對象相等
                return i;
            }
        }
        return -1;
    }

Stack中的判斷使用了Voter的判斷,爲

public synchronized int lastIndexOf(Object o, int index) {
        if (index >= elementCount)
            throw new IndexOutOfBoundsException(index + " >= "+ elementCount);

        if (o == null) {
            for (int i = index; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = index; i >= 0; i--)
                if (o.equals(elementData[i]))//值相等
                    return i;
        }
        return -1;
    }

LinkedList

鏈表結構的列表, 其中特有的方法:addFirst(E e) ,addLast(E e) ,getFirst() ,getLast() ,removeFirst(),removeLast()
還提供了棧結構的實現與隊列結構的實現
棧:先進後出push() ,pop()
隊列:先進先出offer(),poll()
其插入刪除速度會比數組的快很多,其中沒有做併發處理

小結

java提供了不同的list,開發者需要根據應用場景來選擇合適的list,雖然有些可能寫錯了,希望大家指出糾正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章