jdk原始碼閱讀之——arraylist
首先看一下他的建構函式:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
其實arraylist還有其他的建構函式,可以指定陣列的長度,這裡先從最基本的入手
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
這個DEFAULTCAPACITY_EMPTY_ELEMENTDATA 其實就是一個空的陣列,在這裡的作用就是為了表示這是一個空的的陣列
而elementData 是arraylist真正用來存放資料的地方
那麼可以注意到,初始話完成以後,整個陣列的長度就是0,arraylist 正在開始讓他有長度,是在add操作的時候完成的,下面去看下add操作
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
總共兩端程式碼 後一段好理解,就是給陣列賦值,然後把代表陣列長度的size+1
我們進入ensureCapacityInternal 去看看。注意他的引數,是當前陣列的長度+1
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
從引數名minCapacity 的字面意思我們就能知道,意思是最小的容量,
之後先判斷陣列是不是一個空陣列 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
如果是,我們看下當前需要的最小容量和DEFAULT_CAPACITY
DEFAULT_CAPACITY
是arraylist 的一個常量是10,所以看到這裡我們已經知道arraylist預設的長度是10。 好了這裡取最大的值,所以我們的
`minCapacity
變成了10
我們繼續看下一個函式ensureExplicitCapacity
先看字面意思是明確的確保容量,看來arraylist很謹慎
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
首先會注意到這裡有一個modCount,他其實和現在我們分析的沒關係,這是一個用來記錄操作次數的東西,你增加刪除讀取都會記錄,主要用線上程安全上
然後是minCapacity - elementData.length > 0
其實就是比較大小,如果當前需要的空間minCapacity 大於elementData 能提供的空間,我們就需要擴容,也就是grow操作
否則就完事了,我們知道現在elementData的長度為0,那肯定要擴容了,進入grow看看
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;//拿出現在陣列的長度
//擴容,擴容方式就是原來的長度+原來長度的一半,也就是右移一位
int newCapacity = oldCapacity + (oldCapacity >> 1);
//就我們分析的情況 擴容後的長度是0+0/2還是0
//這裡就看下擴容後的長度能不能滿足最小需要的長度,現在看來是不能的那就用最小需要的長度代替擴容的長度吧
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:
//擴容,現在我們的陣列長度為10啦
elementData = Arrays.copyOf(elementData, newCapacity);
}
初始化分析到這裡就結束了,後面看幾個常用的操作
get set remove 其實真的大同小異
先看get
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
這裡涉及到第一個函式rangeCheck
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
他做了一個判斷,當前請求的位置是不是在陣列的長度範圍內,不是丟擲異常,是的話啥事沒有
然後是elementData
E elementData(int index) {
return (E) elementData[index];
}
這個就沒什麼好講了就是把陣列指定位置取出來返回,但請牢記這個函式,後面都會用到他
現在看remove
public E remove(int index) {
//越界檢查
rangeCheck(index);
//操作記錄
modCount++;
//拿到這個要刪除的點
E oldValue = elementData(index);
int numMoved = size - index - 1;
//這裡的操作就是把要刪除位置後面的資料都向前一定一位
//System.arraycopy(要操作的陣列,開始操作的位置,目標陣列,目標陣列開始的位置,複製的長度)
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
最後看set
public E set(int index, E element) {
//越界檢查
rangeCheck(index);
//拿到舊值
E oldValue = elementData(index);
//賦新的值
elementData[index] = element;
//返回舊值
return oldValue;
}
最後我們看一下迭代器部分的程式碼
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
//我們看到arraylist開始使用哪個奇怪的一直在計數的變數的,先把他複製一份
int expectedModCount = modCount;
//判斷還有沒有下一個
public boolean hasNext() {
//看當前閱讀的指標有沒有超出總長度
return cursor != size;
}
@SuppressWarnings("unchecked")
//這是訪問下一個
public E next() {
//檢查
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
//到下一個節點
cursor = i + 1;
//返回當前遍歷節點的資料
return (E) elementData[lastRet = i];
}
//刪除節點
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
//如果兩個值不相等,說明在我們便利的時候有執行緒動了這個arraylist ,這裡丟擲異常快速失敗!
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
總結一下arraylist 底層是陣列,預設長度是10,可以自主擴充套件,擴充套件的長度是
原陣列的長度+原陣列長度/2 也就是新的陣列是原來的1.5倍