Java從入門到放棄(六)集合框架之ArrayList源碼(2)

       上一篇文章Java從入門到放棄(五)集合框架之ArrayList(1)介紹了ArrayList的構造方法和add方法。對於隨機插入,ArrayList是把要插入位置後面的元素全部後移,然後把元素插入到指定位置,如果集合內元素比較多的時候,如1000個元素,你要在5這個位置插入一個元素,就要把5後面的994個元素全部都後移一格,很消耗性能。

3、擴容方法

private Object[] grow() {
        return grow(size + 1);
    }
private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));
    }

插入一個元素最少需要size+1長度的數組,所以grow(size+1),然後調用了Arrays.copyof函數,第一個參數是原始數組,第二個參數是新數組的長度。

看一下newCapcity函數

private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;    //原始數組的長度
        int newCapacity = oldCapacity + (oldCapacity >> 1);   新數組長度爲原數組的1.5倍,
        if (newCapacity - minCapacity <= 0) {       如果新數組長度小於所要求的最小數組長度值
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)    數組是默認的空集合
                return Math.max(DEFAULT_CAPACITY, minCapacity);    返回默認數組長度和最小長度的最大值,默認長度值爲10
            if (minCapacity < 0) // overflow    參數小於0,拋出異常
                throw new OutOfMemoryError();
            return minCapacity;
        }
        return (newCapacity - MAX_ARRAY_SIZE <= 0)   //MAX_ARRAY_SIZE=Integer.MAX_VALUE-8
            ? newCapacity
            : hugeCapacity(minCapacity);
    }

ArrayList的擴容是1.5倍,在第一個元素插入時會把數組長度設爲默認的10,12行是判斷數組長度是否大於最大值,最大值爲Int值的最大值減去8,即2^31-9,如果小於擴容1.5倍,大於的話就返回Int的最大值。

4、remove

public E remove(int index) {
        Objects.checkIndex(index, size);  //如果index大於size拋出異常

        modCount++;                       //修改次數增加
        E oldValue = elementData(index);  //獲取數組index位置的元素

        int numMoved = size - index - 1;  //要移動元素的個數
        if (numMoved > 0)                 
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);     
		
		//把index後面的元素都往前移一個位置,即elementData中index+1
		//後面的numMoved個元素移動到elementData中以index開始的位置
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

remove和add方法類似,移除是把移除元素後面的全部元素往前移動一個位置,然後返回刪除的值。

public boolean remove(Object o) {
        if (o == null) {  //如果刪除null值
            for (int index = 0; index < size; index++)   //循環查找數組元素刪除
                if (elementData[index] == null) {
                    fastRemove(index);      //刪除index位置的元素
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)  //循環查找數組元素,
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

就是循環遍歷對比刪除指定元素,因爲null和null不相等,所以分了兩種情況。可以看到ArrayList是通過equals對比來刪除指定元素的,所以如果要用到這個方法最好重寫equals和hashcode方法,具體可參考Java從入門到放棄(三)equals和==

看一下fastRemove方法:

 private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work  賦值爲null,讓回收器回收。
    }

其實就是和remove(int)方法一樣,少了一步越界檢查,因爲在上面的方法裏面已經保證了不會出現越界。remove和add方法一樣比較耗性能,因爲要移動指定元素後面所有的元素。

5、set,get方法
public E set(int index, E element) {
        Objects.checkIndex(index, size);  //索引越界檢查
        E oldValue = elementData(index);  //取出舊值
        elementData[index] = element;     //賦值新值
        return oldValue;
    }
public E get(int index) {
        Objects.checkIndex(index, size);
        return elementData(index);
    }

set和get方法都是比較的簡單的方法,就是檢查索引越界然後執行對於的操作。

6、isEmpty,clear,size
public void clear() {
        modCount++;
        final Object[] es = elementData;
        for (int to = size, i = size = 0; i < to; i++)
            es[i] = null;
    }

clear並不是刪除所有的元素,而是把size置爲0,然後把elementData的元素都設爲null,這樣子可以在GC的時候被回收。

public boolean isEmpty() {
        return size == 0;
    }

isEmpty很簡單,就是判斷size是否爲0,

size方法就是返回size屬性

size和length的區別:size是集合內元素的個數,length是集合內數組的長度,如添加第一個元素後,size的值爲1,而length的值是10;

發佈了43 篇原創文章 · 獲贊 38 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章