1. 程式人生 > >jdk原始碼閱讀之——arraylist

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倍