ArrayList相關方法介紹及源碼分析

ArrayList簡介:

java.util.ArrayList 是咱們最經常使用的一個類,ArrayList 底層是動態數組,讀者能夠把它理解爲數組的實現數組

public class ArrayList<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable{

}

如上代碼咱們能夠看到 ArrayList 繼承了 AbstractList() 抽象類,並實現了 List, RandomAccess, Cloneable, Serializable 接口安全

AbstractList :

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {}

能夠看到AbstractList 繼承了 AbstractCollection 接口, 並實現了List 接口dom

AbstractCollection :

public abstract class AbstractCollection<E> implements Collection<E> {}

AbstractCollection 是一個抽象類,實現了Collection 接口,並提供了某些方法的具體實現。ide

Collection:

Collection 是一個頂級接口,是不少集合類的頂級接口,繼承了Iterable ,支持輕量級遍歷其中元素源碼分析

public interface Collection<E> extends Iterable<E> {}

List :

ArrayList 實現了List接口,List 也是一個和Collection 媲美的頂級接口,繼承了Collection 接口ui

public interface List<E> extends Collection<E> {}

它是許多集合類的父類,this

eg:debug

List list = new ArrayList();
List list2 = new LinkedList();

RandomAccess

RandomAccess 也是一個頂級接口,實現了此接口的類支持隨機訪問3d

Cloneable

Cloneable 接口是一個頂級接口,實現了此接口的類支持淺拷貝

Serializable

實現此接口的類支持序列化的功能

類之間的繼承關係如圖

ArrayList 相關方法介紹

trimToSize()

代碼表示

實踐纔是檢驗真理最好的方式:

import java.util.*;

/**
 * 詳述ArrayList 基本用法
 */
public class ArrayListTest {

    private static class SortList implements Comparator<String> {

        @Override
        public int compare(String o1, String o2) {
            Integer i1 = Integer.valueOf(o1);
            Integer i2 = Integer.valueOf(o2);
            if(i1 < i2){
                return -1;
            }else if(i1 == i2){
                return 0;
            }
            return 1;
        }
    }

    // 使用可變參數,可以接受任意個參數
    public Set<String> putSet(String...args){
        Set<String> sets = new HashSet<>();
        for(String str : args){
            sets.add(str);
        }
        return sets;
    }

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("111");
        list.add("222");

        // 在指定位置添加元素
        list.add(0,"333");
        System.out.println(list);

        // 進行外部排序
        list.sort(new SortList());
        System.out.println(list);

        list.clear();
        System.out.println(list.size());

        // 使用addAll添加元素
        ArrayListTest at = new ArrayListTest();
        list.addAll(at.putSet("1","2","3"));

        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
            // 移除全部元素
            it.remove();
        }

        System.out.println("list是否爲空 ? " + list.isEmpty());

        list.add("111");
        // 在指定位置添加一個set集合
        list.addAll(0,at.putSet("1","2","3"));
        System.out.println(list);

        // 是否包含指定元素
        if(list.contains("111")) {
            list.remove("111");
        }
        System.out.println(list);

        System.out.println(list.indexOf("1"));
        // 注意subList()這個方法是左開右閉區間,Java 中不少都是相似的
        System.out.println(list.subList(0,3));

        // 擴大list的容量
        list.ensureCapacity(10);
        // 去掉list空閒的容量
        list.trimToSize();

        // 獲取某個特定的元素
        System.out.println(list.get(1));

        // 建立一個list的雙向鏈表
        ListIterator<String> listIterator = list.listIterator();
        while(listIterator.hasNext()){
            // 移到list的末端
            System.out.println(listIterator.next());
        }
        System.out.println("--------------------------");
        while (listIterator.hasPrevious()){
            // 移到list的首端
            System.out.println(listIterator.previous());
        }

        // 把list轉換爲數組
        Object[] objects = list.toArray();
        System.out.println("objects = " + objects);

    }
}

相關方法源碼分析

源碼的具體分析是根據上面的代碼示例得出,由於只看源碼好像並不能看懂什麼,須要根據具體的代碼一步一步debug 進行跟蹤

add()方法

解釋:添加指定的元素在list的末尾

/**
     * 添加指定的元素在list的末尾
     */
    // 假設第一次添加的是 "111"
    public boolean add(E e) {
        // size是0,因此size + 1 傳的是1
        ensureCapacityInternal(size + 1); 
        // elementData[0] = 111 , size++ = 1
        elementData[size++] = e;
        return true;
    }
    
    // 此方法用來進行list 擴容
    private void ensureCapacityInternal(int minCapacity) {
        // 此時elementData 並無存儲元素,爲0
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            // 則minCapacity 取默認初始容量和minCapacity 的最大值 (取1 和 10的最大值)
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        // 確保清晰的容量(最小容量與List元素的比較)
        ensureExplicitCapacity(minCapacity);
    }

    // 在list中添加了一個元素,因此會致使結構化的修改,"結構化的修改"見下面解釋
    // 此時minCapacity 爲 10
    private void ensureExplicitCapacity(int minCapacity) {
        // 次數 + 1 
        // 這個列表被修改結構的次數(好比添加和刪除元素)會用modCount表示. 結構化修改是指的是可以
        // 改變列表容量的操做,或者其餘方式改變它,致使遍歷的過程會產生錯誤的結果。
        modCount++;

        // overflow-conscious code
        // 10 - 0 > 0 走grow 方法
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /**
     * 增長容量確保容納足夠的元素
     * 
     * 參數傳過來的是10
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        // oldCapacity = 0
        int oldCapacity = elementData.length;
        // newCapacity = 0
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // newCapacity - minCapacity = -10
        if (newCapacity - minCapacity < 0)
            // newCapacity = 10
            newCapacity = minCapacity;
        
        // MAX_ARRAY_SIZE = 數組分配的最大空間 = 2147483639
        // 通常狀況下不會比 MAX_ARRAY_SIZE 還要大
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        // 底層仍是用的System.arraycopy(), 關於System.arrayCopy() 讀者能夠參考個人另外一篇博客
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

相關經常使用的基本數據類型包裝類的值: Java基本數據類型包裝類經常使用的值

add(int index, E element)

解釋:在list中指定位置插入指定的元素,若是當前位置有元素,就移動當前位置的元素

/**
     * 在list中指定位置插入指定的元素,若是當前位置有元素,就移動當前位置的元素
     * 要插入的位置的後面全部元素的位置向前 + 1
     *
     */
    public void add(int index, E element) {
        // 檢查 0 這個位置是否越界
        rangeCheckForAdd(index);

        // 再也不贅述,讀者能夠自行debug
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        // 由於從當前位置插入元素,因此當前位置及後面的元素都會向後移動
        // 使用System.arraycopy 進行數組複製
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        // 爲當前元素賦值
        elementData[index] = element;
        size++;
    }

    /**
     * 爲add 和 addall 提供的範圍檢查, 不符合條件,拋出IndexOutOfBoundsException 異常
     */
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

Clear()

解釋:移除列表中的全部元素

/**
     * 移除list列表中全部的元素,列表會變爲空列表在調用此方法後
     *
     */
    public void clear() {
        // 修改次數 + 1
        modCount++;

        // clear to let GC do its work
        // 把每一個變量置空,GC進行回收
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        // 列表的長度變爲0
        size = 0;
    }

這個方法的源碼理解起來仍是比較簡單的

addAll(Collection<? extends E> c)

解釋: 把一個Collection集合添加到list末尾

/**
     * 把一個Collection集合(實現了此接口的類)添加到list的末尾,按着迭代的順序返回。
     * 此操做的行爲是若是在此方法調用的過程當中修改了Collection(實現了此接口的類)的話,
     * 那麼這個操做不會成功
     */
    public boolean addAll(Collection<? extends E> c) {
        // 把Collection 轉換爲 Object[] 數組
        Object[] a = c.toArray();
        // 數組中有三個元素
        int numNew = a.length;
        // 由於上面的操做調用了一次list.clear()方法,因此list.size = 0
        ensureCapacityInternal(size + numNew);  // Increments modCount
        // 一句話解釋: 把a 數組中0個位置的元素 複製到 elementData數組中 第size個位置的元素,
        // 複製的長度爲 numNew
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

    // toArray()方法: 

    /**
     * 返回一個數組,包含了全部的元素(從第一個元素到最後一個元素)
     * 返回的數組是很"安全的"由於列表沒有引用能夠維持(換句話說,這個方法必須分配一個新數組)
     * 調用者所以能夠任意修改返回的數組
     * 這個方法是數組 和 集合之間的橋樑
     */
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

iterator(), hasNext(), next()

解釋:Iterator方法用於遍歷list中的元素,返回一個Itr 的內部類,hasNext()方法用於判斷list 中是否還有未遍歷的元素,next()方法用於獲取下一個元素

/**
     * 以適當的順序返回此列表中元素的迭代器
     * 返回的iterator 支持fail-fast 機制
     */
    public Iterator<E> iterator() {
        return new Itr();
    }

    /**
     * Itr 是一個內部類,實現了Iterator接口,可支持快速遍歷
     */
    private class Itr implements Iterator<E> {
        // 下一個元素返回的下標
        int cursor;       // index of next element to return
        // 最後一個元素返回的下標, 若是沒有返回-1
        int lastRet = -1; // index of last element returned; -1 if no such
        // expectedModCount 指望的修改次數,默認是和modCount(修改次數相同,用於iterator判斷fail-fast機制)
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            // 判斷遍歷的過程當中是否觸發fail-fast機制
            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() {
            // 若是lastRet < 0,說明 lastRet 沒有被改變,
            // 因此應該是沒有調用next()就調用了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();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        // 若是修改次數不知足預期修改次數的話,拋出異常
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

addAll(int index,Collection<? extends E> c)

解釋:在某個位置添加Collection集合

/**
     * 在指定的位置下標插入一個Collection集合
     */
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount

        // 須要移動的元素個數
        int numMoved = size - index;
        if (numMoved > 0)
            // 第一次數組複製,從elementData中的index位置開始,複製到index + numNew位置上,複製numMoved個元素
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);

        // 第二次數組複製,從a 數組中的第0個位置開始,複製到elementData第index位置上你,複製numNew個元素
        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }

contains(Object o)

解釋:判斷list列表是否包含某個元素

/**
     * 返回true,若是這個列表包含指定的元素
     * 更進一步來講,當且僅當list包含至少一個元素的狀況下,返回true
     */
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

    /**
     * 返回列表中第一次出現指定元素的下標值,若是不包含指定元素,則返回-1。
     * 更進一步來講,返回最小的索引當(o == null ? get(i) == null : o.equals(get(i)))的時候
     * 或者返回-1 沒有此下標值
     *
     */
    public int indexOf(Object o) {
        // 若是o這個對象等於null,就判斷elementData中是否有空元素,若是有,返回
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            // 若是不爲null,返回這個值的存儲位置
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

remove(Object o)

解釋:移除list中的某個元素

/**
     * 若是存在,則移除list中某個第一次出現的元素。若是這個list不包含指定元素,就不會改變
     *
     */
    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)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }

indexOf(Object o)

解釋:檢索某個元素的位置

此源碼和contains(Object o)中調用的indexOf 源碼相同

subList(int fromIndex, int toIndex)

解釋:返回list列表的一個片斷

/**
     * 返回list列表中的一部分視圖(至關於list片斷),[fromIndex,toIndex),若是fromIndex 和
     * toIndex 相同的話,代表這個list爲空,這個返回的list被返回,因此在list中並無結構的改變
     * 這個返回的list片斷支持全部的list操做
     */
    public List<E> subList(int fromIndex, int toIndex) {
        // subList 範圍檢查
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }

    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
    }

    private class SubList extends AbstractList<E> implements RandomAccess {
        
        private final AbstractList<E> parent;
        private final int parentOffset;
        private final int offset;
        int size;

        SubList(AbstractList<E> parent,
                int offset, int fromIndex, int toIndex) {
            this.parent = parent;
            this.parentOffset = fromIndex;
            this.offset = offset + fromIndex;
            this.size = toIndex - fromIndex;
            this.modCount = ArrayList.this.modCount;
        }
    }

ensureCapacity(int minCapacity)

解釋:擴大list的容量

/**
     * 增長ArrayList實例的容量,若是必須的話,確保它能持有最小容量的元素
     */
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

trimToSize()

解釋:去掉list空閒的容量

/**
     * 去掉ArrayList中的多餘空間
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

sort(Comparator<? super E> c)

sort 方法接收一個自定義比較器進行自定義比較,下面來看具體的源碼

@Override
    @SuppressWarnings("unchecked")
    public void sort(Comparator<? super E> c) {
        // 根據上面代碼分析,此時modCounnt 已經被修改過三次(添加了三個元素)
        final int expectedModCount = modCount;
        // 數組外部排序
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }
相關文章
相關標籤/搜索