ArrayList初始容量和擴容機制內容部分源碼分析,以及和LinkedList的區別

ArrayList

ArrayList相當於是一個動態類型的順序表,底層是用數組實現的,所以適合隨機的查找和遍歷,不適合插入和刪除
需要注意的幾個點:

  • 初始容量
    調用無參的構造方法時,默認會構造一個初始大小爲10的數組,下面是部分源碼:
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;
    
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

有些小夥伴看到這塊可能會有點疑惑,DEFAULTCAPACITY_EMPTY_ELEMENTDATA明明初始化是一個空數組,爲什麼要說構建了一個初始容量爲10的空列表呢,見下:

	//只是摘錄部分源碼 + 本可愛的理解
	public boolean add(E e) {
		//當調用add方法時,首先調用ensureCapacityInternal(int minCapacity)
		//此時因爲list裏沒有元素,所以size = 0,也就是說minCapacity = size + 1 =1,
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    
     private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        	//由於minCapacity =1 < DEFAULT_CAPACITY,所以minCapacity=10;
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }

ArrayList的擴容機制:

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    private void grow(int minCapacity) {
        // 把當前數組的長度記爲之前的容量大小
        int oldCapacity = elementData.length;
        // 新的容量 = 舊的容量 + (舊的容量>>1)
        // 也就是說新容量 = 舊容量的1.5倍(>>相當於除以2)
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果新容量是否小於最小需要擴容的容量,
        //如果小於則將新容量設爲最小需要的容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //然後檢查新容量是否比數組最大的長度還大
        //如果是則調用hugeCapacity方法繼續確定新容量的大小
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 調用數組的copyOf(原始數組, 新數組長度)將原來的elementData內容複製到容量爲newCapacity大小的新數組中,並將結果賦給elementData
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

LinkedList

LinkedList 底層是不帶頭的雙向鏈表,由於是用鏈表實現的,所以查找慢,但增刪元素快

ArrayList和LinkedList區別:

ArrayList LinkedList
存儲結構 連續空間 鏈式結構
是否支持隨機訪問
任意位置插入/刪除元素的時間複雜度 O(N) O(1)
是否需要擴容 在插入期間可能需要擴容(因爲底層是連續的空間,空間一旦給好,那麼大小就確定好了) 不需要
應用場景 存儲+大量訪問元素 大量任意位置插入刪除元素

Q: 他們兩個的空間利用率誰高一些呢?

  • 不能確定,因爲:
  1. 單純從存儲空間的角度來看,ArrayList每個節點只需要存儲元素就可以 ,而LinkedList除了要存儲節點還要存儲節點和節點之間的關係
  2. 但是插入期間ArrayList如果需要擴容,因爲ArrayList擴容是按照1.5倍擴的,空間沒有佔滿的話,他的利用率會低一點
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章