ArrayList源码分析

ArrayList源码分析

ArrayList作为Collection的实现类之一,在日常开发中会经常被用到,绝大部分Java Programmer都很熟悉ArrayList提供的各种操作方法,但是真正了解其内部实现的又有多少人呢?今天通过我们通过阅读源码的方式,重新学习下ArrayList并了解其内部的实现。

1、什么是ArrayList?
先看下JDK源码中对ArrayList的介绍,如下:

Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)

ArrayList是实现了List接口可调整大小的数组。实现了所有可选的List操作,并允许所有类型元素,包括null元素。除了实现List接口之外,该类还提供了一些方法来操作用于存储List的内部数组的大小。(这个类大致相当于Vector,只是它是非同步的。)

The size , isEmpty, get, set,iterator, and listIterator operations run in constant time. The add operation runs in amortized constant time, that is, adding n elements requires O(n) time. All of the other operations run in linear time (roughly speaking). The constant factor is low compared to that for the LinkedList implementation.

ArrayList的size、isEmpty、get、set、iterator和listIterator操作在常量时间内运行。add操作在平摊常数时间内运行,也就是说,添加n个元素需要O(n)时间。所有其他操作都在线性时间内运行(粗略地说)。与LinkedList实现相比,常量因素要低。

Each ArrayList instance has a capacity. The capacity is the size of the array used to store the elements in the list. It is always at least as large as the list size. As elements are added to an ArrayList, its capacity grows automatically. The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.

每个ArrayList实例都有一个容量。容量是用于存储列表中元素的数组的大小。它总是至少和列表大小一样大。当元素被添加到ArrayList中时,它的容量会自动增长。除了添加一个元素具有恒定的平摊时间代价之外,没有指定增长策略的细节。

简单总结下,ArrayList具有以下特点:

  1. ArrayList实现了List接口,实现了List接口定义的所有操作。
  2. ArrayList内部使用数组来存储List的元素,内部的数组大小可以自动扩容,也可以通过提供方法指定ArrayList的大。
  3. ArrayList内部使用数组,查询和修改元素速度快,插入和删除速度慢。
  4. ArrayList内部的方法没有使用synchronized修饰,是非线程安全的。
2、ArrayList的属性
ArrayList的属性定义比较简单,如下:
    //默认的初始化容量
    private static final int DEFAULT_CAPACITY = 10;

    //用于空实例的共享空数组实例
    private static final Object[] EMPTY_ELEMENTDATA = {};

    //用于默认大小空实例的共享空数组实例,我们将其与EMPTY_ELEMENTDATA区分开来,以了解添加第一个元素时要扩容多少。
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    //用于存储List元素的数组
    transient Object[] elementData; // non-private to simplify nested class access

    //ArrayList的大小
    private int size;
3、ArrayList的构造方法

ArrayList提供了三种构造方法,分别是:

  1. 默认的构造方法
  2. 指定集合容量的构造方法
  3. 使用给定集合的构造方法
    //指定集合容量的构造方法
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            //如果指定容量大于0,使用指定容量初始化数组
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //如果指定容量小于0,使用空的数组实例
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    //默认的构造方法
    public ArrayList() {
        //使用默认大小的空数组实例
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    //使用给定集合的构造方法
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            //将给定集合转化为数组赋给ArrayList内部的数组
            //此处给定集合返回的可能不是Object数组
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            //如果给定集合为空,使用空的数组实例
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
4、ArrayList的其他方法
    //修改集合的大小
    public void trimToSize() {
        modCount++;//更新ArrayList实例的结构修改次数
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }

    /**
     *  如果需要,请增加此Arraylist实例的容量,以确保它至少可以容纳由minimum capacity参数指定的元素数。
     * @param   minCapacity   需要的最小容量
     */
    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);
        }
    }

    //计算容量
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //如果数组为空,取默认容量和最小扩容量的最大值
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

    //确定内部容量
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    //确定明确的容量
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;//更新ArrayList实例的结构修改次数
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            //调用真正的扩容方法
            grow(minCapacity);
    }

    //数组可以分配的最大容量
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 增加数组的容量确保它至少可以容纳由minimum capacity参数指定的元素数。
     * @param minCapacity 需要的最小容量
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        //旧的容量
        int oldCapacity = elementData.length;
        //新的容量,以1.5倍的速率扩容
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            //如果新的容量小于需要的最小容量,把需要的最小容量赋给新的容量
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            //如果新的容量大于数组可以分配的最大容量,则比较minCapacity与MAX_ARRAY_SIZE的大小
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    //比较minCapacity与MAX_ARRAY_SIZE的大小
    private static int hugeCapacity(int minCapacity) {
        //如果minCapacity<0说明已经溢出,需要抛出OOM
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

    //返回ArrayList实例中的元素个数
    public int size() {
        return size;
    }

    //如果ArrayList实例中元素个数为0,返回true,否则,返回fasle
    public boolean isEmpty() {
        return size == 0;
    }

    //如果ArrayList实例中包含元素o,返回true,否则,返回false
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

    //获取给定元素o在ArrayList实例数组中下标
    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;
        }
        //未找到返回-1
        return -1;
    }

    //获取给定元素o在ArrayList实例数组最后一次出现的下标
    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;
        }
        //未找到返回-1
        return -1;
    }

    //返回ArrayList实例的浅拷贝
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) 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(e);
        }
    }

    //以正确的顺序(从第一个到最后一个元素)返回一个包含ArrayList实例所有元素的Object数组
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

    //以正确的顺序(从第一个到最后一个元素)返回一个包含ArrayList实例所有元素的T类型数组
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            //新建一个运行期类型数组,但是返回的是一个T类型数组
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        //复制数组内容
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

    // 获取给定数组下标对应的元素
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

    //获取给定数组下标对应的元素
    public E get(int index) {
        //校验下标合法性
        rangeCheck(index);
        return elementData(index);
    }

    //将给定数组下标对应的元素替换为element
    public E set(int index, E element) {
        //校验下标合法性
        rangeCheck(index);
        //获取原来index位置的值
        E oldValue = elementData(index);
        //index位置替换为新值
        elementData[index] = element;
        return oldValue;
    }

    //ArrayList实例中添加新的元素e,追加到数组尾部
    public boolean add(E e) {
        //确定内部容量
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

    //在给定位置index插入新的元素element
    public void add(int index, E element) {
        //校验下标合法性
        rangeCheckForAdd(index);
        //确定内部容量
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //数组自身复制,从数组的index位置开始将元素复制到从index+1的位置,复制size-index个元素
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        //将元素插入到index位置
        elementData[index] = element;
        //ArrayList实例的大小加1
        size++;
    }

    //移除给定下标index上的元素
    public E remove(int index) {
        //校验下标合法性
        rangeCheck(index);
        //更新ArrayList实例的结构修改次数
        modCount++;
        //获取给定下标index上的元素
        E oldValue = elementData(index);
        //计算需要移动元素的个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
            //数组自身复制,从数组的index+1位置开始将元素复制到从index的位置,复制numMoved个元素
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //ArrayList实例的大小减1,同时将原来数组最后一个元素置为null
        elementData[--size] = null; // clear to let GC do its work
        return oldValue;
    }

    //移除ArrayList实例中第一次出现的给定元素o,如果数组中包含给定的元素o返回true,否则返回false
    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
    }

    //清空ArrayList实例中所有元素
    public void clear() {
        //更新ArrayList实例的结构修改次数
        modCount++;
        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            //将所有下标对应的元素置为null
            elementData[i] = null;
        size = 0;
    }

    //使用给定的集合c向ArrayList实例的末尾追加元素
    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        //确定内部容量
        ensureCapacityInternal(size + numNew);  // Increments modCount
        //从elementData数组的末尾下标开始拷贝数组a的所有元素
        System.arraycopy(a, 0, elementData, size, numNew);
        //计算出ArrayList实例新的大小
        size += numNew;
        return numNew != 0;
    }

    //使用给定的集合c向ArrayList实例的index位置插入元素
    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)
             //数组自身复制,从数组的index+1位置开始将元素复制到从index的位置,复制numMoved个元素
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);
        //从elementData数组的index下标开始拷贝数组a的所有元素
        System.arraycopy(a, 0, elementData, index, numNew);
        //计算出ArrayList实例新的大小
        size += numNew;
        return numNew != 0;
    }

    //删除ArrayList实例从fromIndex至toIndex位置的元素
    protected void removeRange(int fromIndex, int toIndex) {
        modCount++;
        int numMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved);
        // clear to let GC do its work
        int newSize = size - (toIndex-fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }

    //校验下标的合法性
    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));
    }

    //构造outOfBoundsMsg
    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

    //删除ArrayList实例中包含的集合c的所有元素
    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }

    //仅保留ArrayList实例中包含的集合c的所有元素
    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(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;
    }

    //将ArrayList实例序列化至输出流中
    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();
        }
    }

    //从输入流中反序列化出ArrayList实例
    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
            int capacity = calculateCapacity(elementData, size);
            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, 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();
            }
        }
    }

    //从给定的下标index开始返回迭代器实例(ListIterator类型)
    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }

    //返回迭代器实例
    public ListIterator<E> listIterator(ListIterator类型) {
        return new ListItr(0);
    }

    //返回迭代器实例(Iterator)类型
    public Iterator<E> iterator() {
        return new Itr();
    }
   
    //返回ArrayList实例从fromIndex至toIndex的视图
    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 + ")");
    }

ArrayList的扩容依赖的核心方法就是grow(int minCapacity),此方法保证了ArrayList在插入或者尾部追加元素时可以动态扩容。

5、总结

至此,我们通过分析源码分方式学习了ArrayList。再次总结下其特点:

  1. ArrayList的内部使用数组存储元素,查询和修改元素速度快,插入和删除速度慢。与数组有所区别的是,可以动态扩容。
  2. ArrayList内部的方法没有使用synchronized修饰,是非线程安全的,而Vector是线程安全的。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值