Java容器框架(二)--ArrayList實現原理
阿新 • • 發佈:2018-12-11
1. 簡介
在Java容器框架(一)--概述篇 中,對ArrayList做了一些簡單的介紹,它在List家族中具有很重要的角色,它的類繼承關係如下:
public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
本篇文章中將會詳細講解ArrayList的實現原理,分析其原理當然是從其方法入手,本文涉及到的方法主要如下圖所示:
2. ArrayList() & ArrayList(int initialCapacity)
這兩個方法都屬於ArrayList的建構函式,一個是預設無參構造,一個是指定一個初始大小的有參構造,下面我們先來分析無參建構函式。
- ArrayList()
// 預設時候 容器的大小 private static final int DEFAULT_CAPACITY = 10; // 預設情況 空陣列 private static final Object[] EMPTY_ELEMENTDATA = {}; // 儲存元素的陣列 transient Object[] elementData; // non-private to simplify nested class access // 容器中元素的大小 private int size; public ArrayList() { super(); // 呼叫的是父類(AbstractList)的建構函式 this.elementData = EMPTY_ELEMENTDATA; } protected AbstractList() { }
上面程式碼中已經給予了充分的註釋,在物件初始化的時候,定義一個初始容器常量大小DEFAULT_CAPACITY為10,初始化一個為空的陣列常量(這兩個引數主要用於預設情況下使用),對於無參建構函式,僅僅只是初始化了當前容器中的元素集合為一個空陣列。
那麼有參構造是怎樣的呢?
public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); this.elementData = new Object[initialCapacity]; }
同樣,程式碼也非常簡單,初始化容器中存放元素的陣列大小為傳入的initialCapacity,注意此處並沒有設定size的值等於initialCapacity,因為size是表示容器中元素的個數。
3. boolean add(E e) & add(int index, E element)
通過方法名就可以知道,這兩個方法都是向容器中新增元素,它倆有啥區別呢?下面通過原始碼來詳細講解。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
// 判斷當前容器是否為空,為空則初始化一個傳入值和預設值中大的那個數作為初始化陣列的大小
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
// 該變數定義在AbstractList類中,主要用於記錄列表記錄的次數
protected transient int modCount = 0;
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 如果所需容量大於當前陣列的容量,則需要對陣列進行擴容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
// 容器中最大容量,這裡減8的意義在於部分虛擬機器記憶體中存放陣列需要存放一個頭部資訊,
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 擴容策略,擴大到之前容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 擴容1.5倍後容量還是不夠,則選擇傳遞過來的資料作為容量大小
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 新的容量如果大於最大容量,則需要進行再次檢查
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
}
未完待續。。。