ArrayList源碼剖析

構造函數:有3個構造函數
1)在jdk源碼中ArrayList無參的構造函數,默認初始化大小是10;
2)帶有指定大小參數的構造函數
3)帶有集合參數的構造函數

一、確定ArrarList的容量
1、若ArrayList的容量不足以容納當前的全部元素,設置新的容量 = (原始容量 * 3) / 2 + 1。
2、如果擴容後容量還是不夠,則直接將minCapacity設置爲當前容量。

    public void ensureCapacity(int minCapacity) { 
        // 將“修改統計數”+1,該變量主要是用來實現fail-fast機制的     
        modCount++;                  
        int oldCapacity = elementData.length;  
        // 若當前容量不足以容納當前的元素個數,設置新的容量=“(原始容量x3)/2 + 1”  
        if (minCapacity > oldCapacity) {  
            Object oldData[] = elementData;    
            int newCapacity = (oldCapacity * 3)/2 + 1;  
            //如果還不夠,則直接將minCapacity設置爲當前容量  
            if (newCapacity < minCapacity)    
                newCapacity = minCapacity;    
            elementData = Arrays.copyOf(elementData, newCapacity);    
        }    
}

二、添加元素

    public boolean add(E e) {    
        ensureCapacity(size + 1);    // 確定ArrayList的容量大小
        elementData[size++] = e;    // 添加e到ArrayList中
        return true;    
    }
將Element添加到ArrayList的指定位置    
    public void add(int index, E element) {    
        if (index > size || index < 0)    
            throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);    
        ensureCapacity(size+1);          //確定ArrarList的容量   
        //將index位置及後面的元素都往後移一位
        System.arraycopy(elementData, index, elementData, index + 1, size - index);    
        elementData[index] = element;    //將e添加到index位置
        size++;    
    }

三、獲取index位置的元素值

    public E get(int index) {    
        RangeCheck(index);    
        return (E) elementData[index];    
    }

四、設置index位置的值爲element

  public E set(int index, E element) {    
        RangeCheck(index);    
        E oldValue = (E) elementData[index];    
        elementData[index] = element;    
        return oldValue;    
    }

五、刪除ArrayList指定位置的元素

    public E remove(int index) {    
        RangeCheck(index);                  //檢查索引index是否合理
        modCount++;    
        E oldValue = (E) elementData[index];    //保存要刪除位置的元素
        int numMoved = size - index - 1;        //得到要移動的元素的個數
        if (numMoved > 0)    
            System.arraycopy(elementData, index+1, elementData, index, numMoved);    
        elementData[--size] = null;             //因爲都往後移了一位,所以最後一個元素要置空    
        return oldValue;    
}
刪除元素    
 public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
}     
    private void fastRemove(int index) {    
        modCount++;    
        int numMoved = size - index - 1;    
        if (numMoved > 0)         //從"index+1"開始,用後面的元素替換前面的元素。
            System.arraycopy(elementData, index+1, elementData, index, numMoved);  
        elementData[--size] = null;   //將最後一個元素設爲nul   
}

六、ArrayList是否包含Object(o)

    public boolean contains(Object o) {    
        return indexOf(o) >= 0;    
    }

正向查找,返回元素的索引值

    public int indexOf(Object o) {    
        if (o == null) {    
            for (int i = 0; i < size; i++)    
                if (elementData[i]==null)    
                    return i;    
         } else {    
             for (int i = 0; i < size; i++)    
               if (o.equals(elementData[i]))    
                    return i;    
         }    
         return -1;    
        }
    }

七、返回ArrayList的Object數組

    public Object[] toArray() {    
        return Arrays.copyOf(elementData, size);    
    }

八、將集合c追加到ArrayList中

    public boolean addAll(Collection<? extends E> c) {    
        Object[] a = c.toArray();          //得到集合實際保存元素的數組
        int numNew = a.length;    
        ensureCapacity(size + numNew);  //確定添加集合後ArrayList的容量合理    
        System.arraycopy(a, 0, elementData, size, numNew);   //利用System.arraycopy方法將數組拷貝到ArrayList集合的數組中 
        size += numNew;    
        return numNew != 0;    
    }

分析ArrayList源碼比較重要的幾點總結:
1、ArrayList是如何確定容量的—->調用ensureCapacity方法。

2、ArrayList是基於數組的,所以獲取元素和設置元素都是這樣的形式:elementData[index],只需獲取到數組索引就可以了。

3、在ArrayList源碼中,大量使用了System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
src:源數組; srcPos:源數組要複製的起始位置; dest:目的數組; destPos:目的數組放置的起始位置; length:複製的長度。
比如ArrayList的增加、刪除、將集合c追加到ArrayList中這三種操作,都使用了這個方法。

4、Arrays類的靜態方法:copyOf(T[] original, int newLength)
original - 要複製的數組 ; newLength - 要返回的副本的長度 ; newType - 要返回的副本的類型
比如ArrayList的toArray()方法就使用了Arrays.copyOf方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章