ArrayList 源码解析

来源:互联网 发布:网络直播用户规模 编辑:程序博客网 时间:2024/05/16 10:54

本解析源码来自JDK1.7

ArrayList 概要

  • 继承Collection接口,实现了随机存取,自动扩容
  • 内部使用数组进行存储,size表示List中元素的个数
            private transient Object[] elementData;            private int size;
  • 允许null值
  • 与Vector基本相同,但是ArrayList是非同步的,可以使用 List list = Collections.synchronizedList(new ArrayList(...))做同步
  • ArrayList的线性操作比LinkedList的操作的常数项系数要小
  • 有fast-fail机制

一些常量

  • 没有指定ArrayList初始容量,首次添加元素时ArrayList会扩展到长度为10
  • 没有指定ArrayList初始容量,且没有添加元素之前,内部数组为空
  • ArrayList的长度扩展是不会超过Integer.MAX_VALUE-8
DEFAULT_CAPACITY = 10 Object[] EMPTY_ELEMENTDATA = {}MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 

实现接口

public class ArrayList<E> extends AbstractList<E>        implements List<E>, RandomAccess, Cloneable, java.io.Serializable  
  • List 包含了ArrayList的主要操作方法的描述
  • RandomAccess 标志接口,表明随机访问效率高
  • Cloneable 标志接口,表明可以进行深拷贝
  • Serializable 可序列化

构造函数

主要有三种构造方式
- 给定初始大小,创建initialCapacity的数组
- 不给定大小,使用空数组
- 给定另个一Collection c,将集合c的转换为数组,拷贝数组作为成员数组,原集合大小作为size

    public ArrayList(int initialCapacity) {        super();        if (initialCapacity < 0)            throw new IllegalArgumentException("Illegal Capacity: "+                                               initialCapacity);        this.elementData = new Object[initialCapacity];    }     public ArrayList() {        super();        this.elementData = EMPTY_ELEMENTDATA;    }    public ArrayList(Collection<? extends E> c) {        elementData = c.toArray();        size = elementData.length;        // c.toArray might (incorrectly) not return Object[] (see 6260652)        if (elementData.getClass() != Object[].class)            elementData = Arrays.copyOf(elementData, size, Object[].class);    } 

List 接口主要方法

public interface List<E> extends Collection<E> {    // Query Operations    int size();    boolean isEmpty();    boolean contains(Object o);    Iterator<E> iterator();    Object[] toArray();    <T> T[] toArray(T[] a);    // Modification Operations    boolean add(E e);    boolean remove(Object o);    // Bulk Modification Operations    boolean containsAll(Collection<?> c);    boolean addAll(Collection<? extends E> c);    boolean addAll(int index, Collection<? extends E> c);    boolean removeAll(Collection<?> c);    boolean retainAll(Collection<?> c);    void clear();    // Comparison and hashing    boolean equals(Object o);    int hashCode();    // Positional Access Operations    E get(int index);    E set(int index, E element);    void add(int index, E element);    E remove(int index);    // Search Operations    int indexOf(Object o);    int lastIndexOf(Object o);    // List Iterators    ListIterator<E> listIterator();    ListIterator<E> listIterator(int index);    // View    List<E> subList(int fromIndex, int toIndex);}

存入元素

主要方法

  • set(int index, E element) 更新指定位置元素
  • add(E e) 末尾添加元素
  • add(int i,E e) 指定位置后添加元素
  • addAll(Collection c) 末尾批量添加元素
  • addAll(int i, Collection) 指定位置批量添加元素

主要操作

  • 检查插入index的合法性 rangecheck(index)
    • rangeCheck 只检查index是否**大于等于**size,不检查index是否小于零,因为rangeCheck后总是数组操作,所以会抛出ArrayIndexOutOfBoundsException,而不是IndexOutOfBoundsExcepiton
    • rangeCheckForAdd 检查index是否**大于**size或小于0,抛出IndexOutOfBoundsExcepiton
    • 异常信息为 Index:index,Size:size
  • 确保数组有足够容量 ensureCapacityInternal(minCapacity)
  • 将数据拷贝到数组中
    利用Arrays.copyof(originalArray,length)来进行扩容,length指定新数组长度,如果新数组大于原数组长度,其余部分补null
    public E set(int index, E element) {        rangeCheck(index);        E oldValue = elementData(index);        elementData[index] = element;        return oldValue;    }    public boolean add(E e) {        ensureCapacityInternal(size + 1);  // Increments modCount!!        elementData[size++] = e;        return true;    }    public void add(int index, E element) {        rangeCheckForAdd(index);        ensureCapacityInternal(size + 1);  // Increments modCount!!        System.arraycopy(elementData, index, elementData, index + 1,                         size - index);        elementData[index] = element;        size++;    }    public boolean addAll(Collection<? extends E> c) {        Object[] a = c.toArray();        int numNew = a.length;        ensureCapacityInternal(size + numNew);  // Increments modCount        System.arraycopy(a, 0, elementData, size, numNew);        size += numNew;        return numNew != 0;    }    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)            System.arraycopy(elementData, index, elementData, index + numNew,                             numMoved);        System.arraycopy(a, 0, elementData, index, numNew);        size += numNew;        return numNew != 0;    }          private void rangeCheck(int index) {        if (index >= size)            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));    }    private void rangeCheckForAdd(int index) {        if (index > size || index < 0)            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));    }      private String outOfBoundsMsg(int index) {        return "Index: "+index+", Size: "+size;    }      private void ensureCapacityInternal(int minCapacity) {        if (elementData == EMPTY_ELEMENTDATA) {            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);        }        ensureExplicitCapacity(minCapacity);    }  

容量扩展

  • ensureCapacityInternal 如果数组为空,就扩展数组为max(默认大小,给定的minCapacity)大小,否则扩展到给定最小值大小
  • 检查是否有足够容量,如果没有调用grow(minCapacity)进行扩容
  • 默认扩展到1.5倍
  • 如果扩展1.5倍后还是小于给定最小值,就要扩展到的大小为给定最小值
  • 如果要扩展到的大小大于MAX_ARRAY_SIZE,就扩展到 Integer.MAX_VALUE

NOTE
- 共有的扩展数组方法 ensureCapacity(minCapacity)
ArrayList提供了共有的保证容量的方法,一般情况下我们是不用管扩容的事情,但是当我们预计要插入的元素个数比较多时,且数量可估计时,手动确保List容量可以避免频繁的扩容,造成的数据频繁的拷贝,从而提高效率
- 默认初始化会将数组初始化为空,存入元素时直接扩展到DefaultCapacity
如果List为空,只有minCapacity大于DefaultCapacity时才需要扩容,如果List不为空,大于零就需要扩容。
- 扩展的相反操作 trimToSize(int size)
如果设定的size小于数组的长度,用Arrays.copyof(array,length)复制创建一个给定大小的数组

    private void ensureCapacityInternal(int minCapacity) {        if (elementData == EMPTY_ELEMENTDATA) {            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);        }        ensureExplicitCapacity(minCapacity);    }      private void ensureExplicitCapacity(int minCapacity) {        modCount++;        // overflow-conscious code        if (minCapacity - elementData.length > 0)            grow(minCapacity);    }      private void grow(int minCapacity) {        // overflow-conscious code        int oldCapacity = elementData.length;        int newCapacity = oldCapacity + (oldCapacity >> 1);        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:        elementData = Arrays.copyOf(elementData, newCapacity);    }      private static int hugeCapacity(int minCapacity) {        if (minCapacity < 0) // overflow            throw new OutOfMemoryError();        return (minCapacity > MAX_ARRAY_SIZE) ?            Integer.MAX_VALUE :            MAX_ARRAY_SIZE;    }      public void ensureCapacity(int minCapacity) {        int minExpand = (elementData != EMPTY_ELEMENTDATA)            // any size if real element table            ? 0            // larger than default for empty table. It's already supposed to be            // at default size.            : DEFAULT_CAPACITY;        if (minCapacity > minExpand) {            ensureExplicitCapacity(minCapacity);        }    }  

读取元素 get(index)

  • 首先进行index合法性检查,注意不检查小于零的情况,而是由数组抛出ArrayIndexOutOfBoundsException
  • 进行类型转换,返回
    public E get(int index) {        rangeCheck(index);        return elementData(index);    }     @SuppressWarnings("unchecked")    E elementData(int index) {        return (E) elementData[index];    } 

查找

  • 采用逐个遍历的方法进行查找
  • indexOf从前往后找,lastIndexOf从后往前找,
  • contains(e) 调用 indexOf进行查找
    NOTE
    由于允许null值,所以null需要单独处理,而不能用elementData[i].equals(o)
    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;    }     public int lastIndexOf(Object o) {        if (o == null) {            for (int i = size-1; i >= 0; i--)                if (elementData[i]==null)                    return i;        } else {            for (int i = size-1; i >= 0; i--)                if (o.equals(elementData[i]))                    return i;        }        return -1;    }    public boolean contains(Object o) {        return indexOf(o) >= 0;    } 

删除元素

删除元素主要过程:检查参数合法性 其后面元素前移,然后把最后面的元素全部置为null。
- remove(index) 保存原index值用来返回,index后的元素向前拷贝,最后值赋值null以回收

    public E remove(int index) {        rangeCheck(index);        modCount++;        E oldValue = elementData(index);        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        return oldValue;    }  
  • remove(object) 遍历找到对应元素,不需要进行index合法性检查,直接删除
    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    }  
  • removeAll(collection),retainAll(collection)
    • removeAll(collection) 与 retainAll(collection)是两个相反的过程,一个保留给定集合包含的元素,相当于求交集,一个删除给定集合包含的元素,相当于求差集
    • batchRemove 使用双指针的方法,将要保留的值赋值到前面,然后将后面的值置null
      NOTE
      其中finally语句中,r<size 的情况是由于Collection中的contains方法有可能抛出NullPointerException和ClassCastException,如果出现异常,就将当前w之后的值复制到r之后,不再检查是否包含,而后r之后的值依旧赋值为null
    public boolean removeAll(Collection<?> c) {        return batchRemove(c, false);    }     public boolean retainAll(Collection<?> c) {        return batchRemove(c, true);    }      private boolean batchRemove(Collection<?> c, boolean complement) {        final Object[] elementData = this.elementData;        int r = 0, w = 0;        boolean modified = false;        try {            for (; r < size; r++)                if (c.contains(elementData[r]) == complement)                    elementData[w++] = elementData[r];        } finally {            // Preserve behavioral compatibility with AbstractCollection,            // even if c.contains() throws.            if (r != size) {                System.arraycopy(elementData, r,                                 elementData, w,                                 size - r);                w += size - r;            }            if (w != size) {                // clear to let GC do its work                for (int i = w; i < size; i++)                    elementData[i] = null;                modCount += size - w;                size = w;                modified = true;            }        }        return modified;    }

Fast-Fail机制

  • 源码中凡是修改List结构(插入,删除,打乱顺序,调整容量,不包含set更新元素),都会涉及到modCount++
  • 在ArrayList类创建迭代器之后,除非通过迭代器自身remove或add对列表结构进行修改,否则在其他线程中以任何形式对列表进行修改,迭代器马上会抛出异常,快速失败。
  • 该机制通过检查modCount的值来确定是否迭代过程中有其他线程对列表进行修改
        private void checkForComodification() {            if (ArrayList.this.modCount != this.modCount)                throw new ConcurrentModificationException();        }  

复制方法 Clone

浅拷贝,拷贝引用,而非创建新对象,如果引用指向的对象改变也会跟着改变

    public Object clone() {        try {            @SuppressWarnings("unchecked")                ArrayList<E> v = (ArrayList<E>) super.clone();            v.elementData = Arrays.copyOf(elementData, size);            v.modCount = 0;            return v;        } catch (CloneNotSupportedException e) {            // this shouldn't happen, since we are Cloneable            throw new InternalError();        }    }  

转换为数组 toArray

  • toArray()返回新的Object数组
  • toArray(T[]) 如果实参数组长度小于List,返回一个新的T类型数组,如果实参数组大于List,执行复制拷贝,将紧邻的后一个置为null(在list不含null时,便于检查List长度),返回实参数组
    public Object[] toArray() {        return Arrays.copyOf(elementData, size);    }     @SuppressWarnings("unchecked")    public <T> T[] toArray(T[] a) {        if (a.length < size)            // Make a new array of a's runtime type, but my contents:            return (T[]) Arrays.copyOf(elementData, size, a.getClass());        System.arraycopy(elementData, 0, a, 0, size);        if (a.length > size)            a[size] = null;        return a;    } 

序列化方法

  • elementData声明为transient是不会被序列化写入的,所以序列化分两步,首先执行通用序列化,然后将数组中的元素逐一读入,或写出
  • 在进行写入的过程中有fast-fail机制,即这个过程中有对list的修改会造成失败
  • 虽然size单独写入了,但是在readObject中这个值并没有用到,为了与clone方法适配
    private transient Object[] elementData;      private void writeObject(java.io.ObjectOutputStream s)        throws java.io.IOException{        // Write out element count, and any hidden stuff        int expectedModCount = modCount;        s.defaultWriteObject();        // Write out size as capacity for behavioural compatibility with clone()        s.writeInt(size);        // Write out all elements in the proper order.        for (int i=0; i<size; i++) {            s.writeObject(elementData[i]);        }        if (modCount != expectedModCount) {            throw new ConcurrentModificationException();        }    }    private void readObject(java.io.ObjectInputStream s)        throws java.io.IOException, ClassNotFoundException {        elementData = EMPTY_ELEMENTDATA;        // Read in size, and any hidden stuff        s.defaultReadObject();        // Read in capacity        s.readInt(); // ignored        if (size > 0) {            // be like clone(), allocate array based upon size not capacity            ensureCapacityInternal(size);            Object[] a = elementData;            // Read in all elements in the proper order.            for (int i=0; i<size; i++) {                a[i] = s.readObject();            }        }    }  

迭代器

  • 迭代器作为ArrayList的内部类,可以直接访问修改ArrayList
  • ArrayList实现了两种迭代器,其中ListIterator除了实现基本的Iterator方法(hasNext,Next,remove),还包含更丰富的方法
  • ListIterator额外实现的方法
    • listIterator(index) 可以指定开始遍历的位置
    • hasPrevious 有没有前驱
    • previous 返回前驱
    • add 实现添加元素
    • set 更新上次访问的元素
    • previousIndex() nextIndex() 返回下一个,和上一个位置
      NOTE
      remove,add,set方法都是改变上次被访问元素位置进行操作,连续调用两次以上就会出现问题
    public ListIterator<E> listIterator(int index) {        if (index < 0 || index > size)            throw new IndexOutOfBoundsException("Index: "+index);        return new ListItr(index);    }    public ListIterator<E> listIterator() {        return new ListItr(0);    }    public Iterator<E> iterator() {        return new Itr();    }      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        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() {            if (modCount != expectedModCount)                throw new ConcurrentModificationException();        }    }    private class ListItr extends Itr implements ListIterator<E> {        ListItr(int index) {            super();            cursor = index;        }        public boolean hasPrevious() {            return cursor != 0;        }        public int nextIndex() {            return cursor;        }        public int previousIndex() {            return cursor - 1;        }        @SuppressWarnings("unchecked")        public E previous() {            checkForComodification();            int i = cursor - 1;            if (i < 0)                throw new NoSuchElementException();            Object[] elementData = ArrayList.this.elementData;            if (i >= elementData.length)                throw new ConcurrentModificationException();            cursor = i;            return (E) elementData[lastRet = i];        }        public void set(E e) {            if (lastRet < 0)                throw new IllegalStateException();            checkForComodification();            try {                ArrayList.this.set(lastRet, e);            } catch (IndexOutOfBoundsException ex) {                throw new ConcurrentModificationException();            }        }        public void add(E e) {            checkForComodification();            try {                int i = cursor;                ArrayList.this.add(i, e);                cursor = i + 1;                lastRet = -1;                expectedModCount = modCount;            } catch (IndexOutOfBoundsException ex) {                throw new ConcurrentModificationException();            }        }    }  

子视图 SubList

  • 首先进行位置检查,如果合法,就调用新建SubList对象
  • ArrayList将自身作为参数传递,也就是说,对SubList的操作其实是对原ArrayList的操作,SubList的方法跟ArrayList相近,只是需要进行index的转换,加上fromIndex
  • SubList 只会返回ListIterator,其ListIterator对象通过匿名内部类的方式定义
    public List<E> subList(int fromIndex, int toIndex) {        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;        }        public E set(int index, E e) {            rangeCheck(index);            checkForComodification();            E oldValue = ArrayList.this.elementData(offset + index);            ArrayList.this.elementData[offset + index] = e;            return oldValue;        }        public E get(int index) {            rangeCheck(index);            checkForComodification();            return ArrayList.this.elementData(offset + index);        }        public int size() {            checkForComodification();            return this.size;        }        public void add(int index, E e) {            rangeCheckForAdd(index);            checkForComodification();            parent.add(parentOffset + index, e);            this.modCount = parent.modCount;            this.size++;        }        public E remove(int index) {            rangeCheck(index);            checkForComodification();            E result = parent.remove(parentOffset + index);            this.modCount = parent.modCount;            this.size--;            return result;        }        protected void removeRange(int fromIndex, int toIndex) {            checkForComodification();            parent.removeRange(parentOffset + fromIndex,                               parentOffset + toIndex);            this.modCount = parent.modCount;            this.size -= toIndex - fromIndex;        }        public boolean addAll(Collection<? extends E> c) {            return addAll(this.size, c);        }        public boolean addAll(int index, Collection<? extends E> c) {            rangeCheckForAdd(index);            int cSize = c.size();            if (cSize==0)                return false;            checkForComodification();            parent.addAll(parentOffset + index, c);            this.modCount = parent.modCount;            this.size += cSize;            return true;        }        public Iterator<E> iterator() {            return listIterator();        }        public ListIterator<E> listIterator(final int index) {            checkForComodification();            rangeCheckForAdd(index);            final int offset = this.offset;            return new ListIterator<E>() {                int cursor = index;                int lastRet = -1;                int expectedModCount = ArrayList.this.modCount;                public boolean hasNext() {                    return cursor != SubList.this.size;                }                @SuppressWarnings("unchecked")                public E next() {                    checkForComodification();                    int i = cursor;                    if (i >= SubList.this.size)                        throw new NoSuchElementException();                    Object[] elementData = ArrayList.this.elementData;                    if (offset + i >= elementData.length)                        throw new ConcurrentModificationException();                    cursor = i + 1;                    return (E) elementData[offset + (lastRet = i)];                }                public boolean hasPrevious() {                    return cursor != 0;                }                @SuppressWarnings("unchecked")                public E previous() {                    checkForComodification();                    int i = cursor - 1;                    if (i < 0)                        throw new NoSuchElementException();                    Object[] elementData = ArrayList.this.elementData;                    if (offset + i >= elementData.length)                        throw new ConcurrentModificationException();                    cursor = i;                    return (E) elementData[offset + (lastRet = i)];                }                public int nextIndex() {                    return cursor;                }                public int previousIndex() {                    return cursor - 1;                }                public void remove() {                    if (lastRet < 0)                        throw new IllegalStateException();                    checkForComodification();                    try {                        SubList.this.remove(lastRet);                        cursor = lastRet;                        lastRet = -1;                        expectedModCount = ArrayList.this.modCount;                    } catch (IndexOutOfBoundsException ex) {                        throw new ConcurrentModificationException();                    }                }                public void set(E e) {                    if (lastRet < 0)                        throw new IllegalStateException();                    checkForComodification();                    try {                        ArrayList.this.set(offset + lastRet, e);                    } catch (IndexOutOfBoundsException ex) {                        throw new ConcurrentModificationException();                    }                }                public void add(E e) {                    checkForComodification();                    try {                        int i = cursor;                        SubList.this.add(i, e);                        cursor = i + 1;                        lastRet = -1;                        expectedModCount = ArrayList.this.modCount;                    } catch (IndexOutOfBoundsException ex) {                        throw new ConcurrentModificationException();                    }                }                final void checkForComodification() {                    if (expectedModCount != ArrayList.this.modCount)                        throw new ConcurrentModificationException();                }            };        }        public List<E> subList(int fromIndex, int toIndex) {            subListRangeCheck(fromIndex, toIndex, size);            return new SubList(this, offset, fromIndex, toIndex);        }        private void rangeCheck(int index) {            if (index < 0 || index >= this.size)                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));        }        private void rangeCheckForAdd(int index) {            if (index < 0 || index > this.size)                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));        }        private String outOfBoundsMsg(int index) {            return "Index: "+index+", Size: "+this.size;        }        private void checkForComodification() {            if (ArrayList.this.modCount != this.modCount)                throw new ConcurrentModificationException();        }    } 
1 0
原创粉丝点击