ArrayList源码分析

1. ArrayList继承关系介绍

1.1 ArrayList继承关系图
1.2 ArrayList的父类及接口介绍

(1)Iterable:实现该接口后可使用迭代器和增强for循环
(2)Collection:集合体系结构的顶级接口
(3)List:有序(插入顺序)、可通过索引访问、允许存在重复元素、允许添加null元素
(4)AbstractCollection:Collection的骨架实现
(5)AbstractList:List的一个"骨架"实现
(6)RandomAccess:一种标记接口,实现了该接口,就表示该实现支持随机访问,进行某些操作时底层会判断是否实现该接口来选择相应的算法
(7)Cloneable:一种标记接口,若不实现该接口,用Object.clone会报错
(8)Serializable:一种标记接口,只要需要将对象转换为字节形式,如进行网络传输或持久化时,就需要实现该接口

2. 源码分析前的一些说明

2.1 数组的创建和拷贝

ArrayList底层数组的动态扩容是通过调用Arrays.copyOf来完成数组的创建和拷贝,拷贝工作实际是由System.arraycopy完成,Arrays.copyOf的重载方法很多,但功能类似,下面仅对其中一个进行说明:

    public static int[] copyOf(int[] original, int newLength) {
        // 新建一个长度为newLength的数组
        int[] copy = new int[newLength];
        // System.arraycopy是本都方法,其方法签名是:System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
        // 对应到这里,就是将original的内容拷贝到copy中,起始位置都是0,拷贝的长度为Math.min(original.length, newLength)
        System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
        return copy;
    }
2.2 溢出问题

举个极端的例子,对x、y是两个类型为int的变量,当x为-2,y为Integer.MAX_VALUE时,x<y的结果为true,而x-y<0的结果为false,因为x-y发生了数据溢出,x-y溢出后的值为Integer.MAX_VALUE。ArrayList底层扩容时会用x-y的形式考虑溢出的情况,这里只要知道x<y与x-y<0不一样即可,不再细究。

2.3 modCount

在ArrayList中多处用到modCount,modCount是AbstractList中的字段,用于并发情况下检测各线程操作是否正确的一种机制。

3. ArrayList源码分析

3.1 ArrayList中的字段
    // 序列化id
    private static final long serialVersionUID = 8683452581122892189L;

    // 默认初始容量
    private static final int DEFAULT_CAPACITY = 10;

    // 共享(因为static)的空Object数组 
    private static final Object[] EMPTY_ELEMENTDATA = {};

    // 共享的空Object数组,用于空构造器中(即用在ArrayList()中)对elementData进行初始化
    // 当添加第一个元素进行扩容时,会进行判断,若elementData就是这个空数组,
    // 则初始容量为DEFAULT_CAPACITY,相比于EMPTY_ELEMENTDATA,可实现快速扩容
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    // ArrayList的底层Object数组
    // 被transient修饰,意味着不会被序列化
    // ArrayList自定义了writeObject/readObject,elementData会在这两个方法中被处理(后面会介绍)
    transient Object[] elementData; // non-private to simplify nested class access

    // 代表数组中元素的个数,elementData.length是数组的实际大小
    // size+1就是下面扩容时的最小容量(minCapacity)
    private int size;
3.2 三种构造器
    // 无参构造器,用DEFAULTCAPACITY_EMPTY_ELEMENTDATA初始化elementData后, 
    // 第一次添加元素时,会将容量初始化为10
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    // 创建指定大小的elementData
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    // 用c初始化elementData
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray(); // 将c转换为数组类型
        if ((size = elementData.length) != 0) {
            // 若elementData中的元素(即c中的元素类型)不是Object类型
            if (elementData.getClass() != Object[].class) 
                // 则对数组进行拷贝,拷贝后的数组大小为size(即当前元素个数),类型为Object[]
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // 元素个数为0,则用EMPTY_ELEMENTDATA进行初始化
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
3.3 增加元素

(1)add(E e)及扩容

    // 将元素添加到末尾
    public boolean add(E e) {
        // 进行扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

    // ensureCapacityInternal在内部扩容时调用
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    // 该方法与ensureCapacity方法的作用类似,但是它是被private修饰的
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        // 当用无参构造器实例化且第一次调用时,elementData总是会被初始化为10
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code(考虑了溢出的情况)
        if (minCapacity - elementData.length > 0) // 需要的最小容量是否超过当前elementData的容量
            grow(minCapacity); // 超过则扩容
    }

    private void grow(int minCapacity) {
        // overflow-conscious code (考虑了溢出的情况)
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1); // 每次扩容为原来的1.5倍
        if (newCapacity - minCapacity < 0) // 扩容1.5倍后仍无法满足最小容量
            newCapacity = minCapacity; // 那么就用该minCapacity
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 进行数组的扩容和拷贝
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // 溢出
            throw new OutOfMemoryError();
        // 我的机器到这种容量会报错:OutOfMemoryError: Java heap space
        // 或者OutOfMemoryError: Requested array size exceeds VM limit    
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

(2)外部扩容用ensureCapacity

    //该方法被public修饰,如果将要添加很大数量的元素,可提前调用该函数以减少扩容次数
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)   ? 0 : DEFAULT_CAPACITY;

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

(3)其他添加元素的方法

    // 在指定索引处插入元素 
    public void add(int index, E element) {
        rangeCheckForAdd(index); // 边界检查(注意这里index可以等于size)
        // 进行扩容
        ensureCapacityInternal(size + 1);  
        // 将目前index处和它后面的元素整体后移一个位置
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
        elementData[index] = element; // 更新该索引处的值
        size++; // 更新size
    }

    // 将c中所有元素按顺序添加到elementData末尾
    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        // 进行扩容
        ensureCapacityInternal(size + numNew);  
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0; // 注意一下返回值
    }

    // 在指定索引处开始,按序添加c中的元素,与addAll(Collection<? extends E> c)类似 
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

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

        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;
    }
3.4 删除元素

(1)删除单个元素

    // 删除指定索引处的元素
    public E remove(int index) {
        rangeCheck(index); // index不小于size则抛异常

        modCount++;
        E oldValue = elementData(index); // 获取elementData[index]

        int numMoved = size - index - 1; // 计算移除该元素后,需要移动的元素个数(就是该元素后的所有元素的个数)
        
        if (numMoved > 0) // 进行移动(注意一下源数组和目的数组拷贝的起始位置)
            System.arraycopy(elementData, index+1, elementData, index, numMoved);
        
        elementData[--size] = null; // 将最后一个元素置为null

        return oldValue; // 返回被删除元素的值
    }

    // 删除指定元素 
    public boolean remove(Object o) {
        if (o == null) { // ArrayList中允许添加为null的元素
            // 遍历并删除第一个为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); // 该方法与remove(int index)类似,仅仅少了边界检查且没有返回值
                    return true;
                }
        }
        // 未找到与o匹配的元素,返回false
        return false;
    }

    // 与remove类似,只是少了边界检查且无返回值 
    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
    }

(2)删除多个元素

    // 删除指定索引范围的元素 
    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);
        // 将后面的元素设置为null
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }

    // 移除当前链表所有不包含在c中的元素
    public boolean removeAll(Collection<?> c) {
        // c为null则抛异常
        Objects.requireNonNull(c);
        // 批量移除
        return batchRemove(c, false);
    }

    // 保留当前链表所有包含在c中的元素(与removeAll互补) 
    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }

    // complement为true表示保留包含在c中的,为false表示移除包含在c中
    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++)
                // 依据complement为true/false,保留/移除包含在c中的元素
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r]; // 进行移动
        } finally {
            // Preserve behavioral compatibility(兼容性) with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) { // 若 r != size 成立证明抛异常了
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            if (w != size) {
                // 将索引为 w ~ size-1 的元素设置为null
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                // 更新相关字段
                modCount += size - w;
                size = w; 
                
                modified = true;
            }
        }
        return modified;
    }

(3)清空元素

    // 将elementData中所有元素设置为null 
    public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }
3.5 修改元素值

(1)修改单个元素的值

    public E set(int index, E element) {
        rangeCheck(index); // 边界检查
        E oldValue = elementData(index); //取出旧值
        elementData[index] = element; // 替换旧值
        return oldValue; // 返回旧值
    }

(2)替换所有元素的值

    // 对所有值按照传入的operator进行处理并替换原值
    public void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final int expectedModCount = modCount;
        final int size = this.size;
        // 对elementData的所有元素进行替换
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            elementData[i] = operator.apply((E) elementData[i]);
        }
        if (modCount != expectedModCount) { // 替换期间若当前链表被修改则抛异常
            throw new ConcurrentModificationException();
        }
        modCount++;
    }
3.6 查看元素值
    public E get(int index) {
        rangeCheck(index); // 边界检查

        return elementData(index); // 返回元素值
    }

    // 获取指定元素
    E elementData(int index) {
        return (E) elementData[index];
    }
3.7 序列化和反序列化

ArrayList中的elementData是被transient修饰的,表示不被序列化,因为该数组的后面可能存在很多为null的元素,因此ArrayList(其他集合也是如此)中对序列化和反序列化进行了自定义。要进行自定义,除了实现Serializable接口,其次就是要重写方法头为private void writeObject(java.io.ObjectOutputStream s)和private void readObject(java.io.ObjectInputStream s)的两个方法,在序列化/反序列化时,底层会判断是否存在writeObject/readObject,存在的话会通过反射调用这两个方法。下面对这两个方法进行介绍:

    // 序列化时调用
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{

        int expectedModCount = modCount;
        s.defaultWriteObject(); // 将当前类中non-static、non-transient字段写入流中

        s.writeInt(size); // 将elementData的元素个数写入流中

        // 仅写入elementData中的前size个元素,忽略后面为null的元素
        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;
        // 从流中读取当前类中non-static、non-transient的字段
        s.defaultReadObject(); 

        s.readInt(); // 可忽略

        // 进行扩容并读取所有元素
        if (size > 0) {
            // 进行扩容
            int capacity = calculateCapacity(elementData, size);
            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // 从流中按序读取所有元素
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }
3.8 其他方法

(1)sort

    // 底层会调用合适的算法,按照条件c对elementData进行排序
    public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

(2)trimToSize

    // "修剪"elementData,使得elementData的容量与其中的元素个数
    // 相等(也就是使得elementData.length与size相等)
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }

(3)toArray

    public <T> T[] toArray(T[] a) {
        if (a.length < size) 
            // 创建大小为size,类型为a.getClass()的数组,再将该数组转化为T[]类型,
            // 并拷贝elementData中的现有元素到该数组中
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        // a.length >= size,直接拷贝
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

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

(4)indexOf和lastIndexOf

    // 找到第一个匹配的元素,并返回其索引,未找到则返回-1(与remove(Object 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;
    }

    // 与indexOf类似,找到最后一个匹配的元素,并返回其索引,未找到则返回-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;
    }
3.7 内部类

Java中Iterator是用于对Collection(的实现)进行迭代的,它为ArrayList、LinkedList、HashSet等Collection的实现提供了以相同方式迭代、操作元素的机制。Iterator对Enumeration进行了优化和扩充,用于代替Enumeration。Itr、ListItr是ArrayList中的内部类,都用于对元素的迭代,不同点是Itr只能单向迭代,而ListItr可进行双向迭代,下面仅对Itr进行说明:

    // ArrayList对AbstractList.Itr进行了优化
    private class Itr implements Iterator<E> {
        int cursor;       // 下一个元素的索引
        int lastRet = -1; // 最后返回的元素对应的索引,若该元素不存在了(如调用remove后),则为-1
        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; // 更新cursor
            return (E) elementData[lastRet = i]; // 更新lastRet
        }

        // 调用remove前需先调用next
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1; // 最后一个元素被删除,将lastRet设置为-1
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        // 调用Consumer.accept对每一个"留下"的元素进行处理
        @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++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。