ArrayList其實就是一個長度可變的數組,看源碼就是知道,就是是一個Object[]。
ArrayList是unsynchronized。
由於底層由數組承載,那麼須要連續的內存空間,因此空間複雜度是O(n)。
若是按下標直接去get(index)或者直接add(e)到數組的尾部,那麼時間複雜度是O(1)。
若是要remove(index),或者add(index,e)那麼時間複雜度爲O(n)。
接下來看一下源碼java
/** * 默認初始容量空間爲10 */ private static final int DEFAULT_CAPACITY = 10; /** * 空的Object數組 */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * add存儲的數組 */ private transient Object[] elementData;
首先來講實例化
ArrayList(int initialCapacity);
實例化能夠直接給出數組的長度,雖然數組能夠本身擴容,可是擴容須要過程的空間複雜度應該是O(2n)由於須要拷貝一個次舊的數組。這個在後面會提到。因此當肯定數組大小的時候,好比或limit肯定了取多少數據,那麼請直接給list固定的長度。
若是用下面的夠早進行實例化,那麼初始的底層數組是一個null,是沒有長度的。數組
public ArrayList() { super(); this.elementData = EMPTY_ELEMENTDATA; }
接着看 add(),第一步先作了增量的變化this
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
而後進入ensureCapacityInternal()方法code
private void ensureCapacityInternal(int minCapacity) { //若是說數組沒有長度的話,須要進行長度賦值 //第一次操做數組的話Math.max(10,1) if (elementData == EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } //此時minCapacity = 10傳入ensureExplicitCapacity() ensureExplicitCapacity(minCapacity); }
再看ensureExplicitCapacity()方法內存
private void ensureExplicitCapacity(int minCapacity) { modCount++; // 若是說add後的長度大於現有的數組長度,說明數組應該擴容了。 if (minCapacity - elementData.length > 0) grow(minCapacity); }
進入grow();ci
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; private void grow(int minCapacity) { // 先得到舊數組的長度 int oldCapacity = elementData.length; //經過右移1位來實現oldCapacity/2,擴容原來的1.5倍(PS.左移一位*2,右移一位/2) int newCapacity = oldCapacity + (oldCapacity >> 1); //若是新的容量能夠放下準備add後的容量 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //若是新擴容後大於Integer.MAX_VALUE - 8,拋出OutOfMemoryError //爲何會-8?javadoc說須要保留一些作head if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //肯定了新的容量後,拷貝,new 新的長度的數組,在賦值 elementData = Arrays.copyOf(elementData, newCapacity); }
雖然List是一個可變數組,可是可變是付出了空間的代價。因此,根據實際狀況去運用。element