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: 他們兩個的空間利用率誰高一些呢?
- 不能確定,因爲:
- 單純從存儲空間的角度來看,ArrayList每個節點只需要存儲元素就可以 ,而LinkedList除了要存儲節點還要存儲節點和節點之間的關係
- 但是插入期間ArrayList如果需要擴容,因爲ArrayList擴容是按照1.5倍擴的,空間沒有佔滿的話,他的利用率會低一點