本文簡單介紹了 ArrayList
,並對擴容,添加,刪除操作的源代碼做分析。能力有限,歡迎指正。
ArrayList是什麼?
ArrayList
就是數組列表,主要用來裝載數據。底層實現是數組 Object[] elementData
,當我們裝載的是基本數據類型 int, long, boolean, shot...的時候我們只能存儲他們對應的包裝類型。
與它類似的是 LinkedList
,和 LinkedList
相比,它的查找和訪問元素的速度較快,但新增,刪除的速度較慢。
線程安全嗎?
線程不安全。
正常使用場景中,ArrayList
都是用來查詢,不會涉及太頻繁的增刪,如果涉及頻繁的增刪,可以使用 LinkedList
。如果需要線程安全就使用 Vector
。
Vector
是 ArrayList
的線程安全版本,實現方式就是在所有方法加上synchronized
,性能較差。
如何擴容?
因爲數組的大小是固定,當容量超出了現有數組的大小,就需要進行擴容。
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 每次擴大原有容量的一半
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果擴大一半後還是無法滿足,則使用minCapacity
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果超過最大size,則獲取最大容量的數組
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);
}
爲什麼說ArrayList插入效率低?
原因有兩點:
- 新增就要檢測容量夠不夠,如果不夠就需要擴容
- 尾部新增比較快,如果是在數組頭部或者中部新增就會慢很多,因爲要把後面的元素全部往後移一位
- 把元素往後移一位使用的是複製
System.arraycopy()
,它是native
方法(java定義了接口,其他語言進行實現),所以比較快
/**
* 添加在尾部
*/
public boolean add(E e) {
// 檢查容量
ensureCapacityInternal(size + 1);
// 添加在尾部
elementData[size++] = e;
return true;
}
/**
* 按指定位置添加
*/
public void add(int index, E element) {
// 檢查index
rangeCheckForAdd(index);
// 檢查容量
ensureCapacityInternal(size + 1);
// index後面的元素全部往後移一位
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
刪除元素效率如何?
效率和新增差不多,都是要移動元素,但是不需要檢查容量和擴容。
public E remove(int index) {
// 檢查index
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
// index後面的元素全部往前移一位
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
適合做隊列嗎?
非常不適合。
隊列是FIFO,在尾巴進,頭部出,出的時候需要移動後面所有數據,效率很低。鏈表比較適合做隊列。
new ArrayList<>(18) 會不會初始化數組大小?
不會初始化數組大小!!!
這是Java Bug。
而且將構造函數與initialCapcity結合使用,然後使用set()方法會拋出異常。
public static void main(String[] args) {
ArrayList<Integer> a = new ArrayList<>(12);
System.out.println(a.size());
a.set(3, 3);
}
總結
- 底層實現是數組
Object[] elementData
- 查找和訪問元素的速度較快,但新增,刪除的速度較慢
- 線程不安全
- 每次擴容原有數組大小的一半
源碼系列文章
本文首發於我的個人博客 http://chaohang.top
作者張小超
轉載請註明出處
歡迎關注我的微信公衆號 【超超不會飛】,獲取第一時間的更新。