ArrayList源码剖析

150 阅读5分钟

ArrayList源码剖析

简介

ArrayList 是 java 集合框架中比较常用的数据结构。继承自 AbstractList,实现了 List 接口。底层基于数组实现容量大小动态变化。允许 null 的存在。同时还实现了 RandomAccess、Cloneable、Serializable 接口,所以ArrayList 是支持快速访问、复制、序列化的。

主要成员变量

	// 默认初始化容量  
	private static final int DEFAULT_CAPACITY = 10;
	// 存储数据的数组
    transient Object[] elementData; // non-private to simplify nested class access
	// 元素个数
    private int size;
	// 被修改次数 主要让迭代器使用
	protected transient int modCount = 0;

主要方法详解

ArrayList

  public ArrayList(int initialCapacity) {
    	//初始化容量大小 > 0 就创建一个长度为initialCapacity的Object数组
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
    	// 空数组
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
  	public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {
			// 如果 c 为ArrayList 直接将 c 的elementData 引用
            if (c.getClass() == ArrayList.class) {
                elementData = a;
            } else {
            //否则copy
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
			//c 为空集合 创建空的ArrayList
        } else {
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }

toArray

返回集合中的所有元素

	public Object[] toArray() {
    	// copy 集合中的存储元素的数组
        return Arrays.copyOf(elementData, size);
    }

add

尾部新增元素

    private void add(E e, Object[] elementData, int s) {
        // 当前容量 = 当前元素个数  需要扩容
        if (s == elementData.length)
			// 扩容
            elementData = grow();
		// 将数组的第 s + 1 个元素设置为 e 即在末尾追加元素
        elementData[s] = e;
		// size + 1
        size = s + 1;
    }

    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
    	// 记录修改次数
        modCount++;
		// 新增元素
        add(e, elementData, size);
        return true;
    }

    public void add(int index, E element) {
    	// 检查要插入的位置的合法性
        rangeCheckForAdd(index);
		// 修改次数 + 1
        modCount++;
        final int s;
        Object[] elementData;
		// 如果当前容量 = 当前元素个数 需要扩容
        if ((s = size) == (elementData = this.elementData).length)
            elementData = grow();
		// 将第 index + 1 (下标为index) 位以及后面的元素向后移动
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
		// 将element 设置到第 index + 1 (下标为index)位
        elementData[index] = element;
		// 容量 + 1
        size = s + 1;
    }

grow

扩容方法

    private Object[] grow(int minCapacity) {
    	// 旧容量大小
        int oldCapacity = elementData.length;
		// 旧容量 > 0 (说明已经添加过元素)     或者 elementData 不等于 DEFAULTCAPACITY_EMPTY_ELEMENTDATA (说明调用的不为无参构造方法)
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
			// 计算新数组的容量
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity, /* minimum growth */
                    oldCapacity >> 1           /* preferred growth */);
			// 将现有的元素拷贝一份到容量为 newCapacity 的新数组
            return elementData = Arrays.copyOf(elementData, newCapacity);
        } else {
			// 否则给默认容量或者要增加容量的最大值
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
        }
    }

    private Object[] grow() {
    	// 将数组长度扩容至 容量 + 1
        return grow(size + 1);
    }

ArraysSupport#newLength

计算新集合的容量

    public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
        // preconditions not checked because of inlining
        // assert oldLength >= 0
        // assert minGrowth > 0
		// oldLength 旧的长度
		// minGrowth 最少要增加的长度
		// prefGrowth 优先增加的长度 为旧元素的1/2
		// 计算为旧容量 + 优先扩容容量与最小扩容容量的最大值  为以后预留空间
        int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
        // prefLength > 0 说明数据没有溢出 超过了 int的最大值 并且 <= int 的最大值 - 8
        
        if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
            return prefLength;
        } else {
        	// 即如果预留扩容数据溢出
            // put code cold in a separate method
            return hugeLength(oldLength, minGrowth);
        }
    }

ArraysSupport#hugeLength

如果1.5倍扩容将超出限制就尽量预留,不能预留就最小容量

    private static int hugeLength(int oldLength, int minGrowth) {
    	// 旧容量 + 最小扩容容量
        int minLength = oldLength + minGrowth;
		// < 0 代表数据溢出 能承载所有元素的最小长度已经数据溢出
        if (minLength < 0) { // overflow
            throw new OutOfMemoryError(
                "Required array length " + oldLength + " + " + minGrowth + " is too large");
		// newLength 中已经判断预留扩容会数据溢出 就将ArrayList容量设置为ArrayList所允许的最大容量 (预留容量)
        } else if (minLength <= SOFT_MAX_ARRAY_LENGTH) {
            return SOFT_MAX_ARRAY_LENGTH;
        } else {
			// 预留超出限制就返回最小容量
            return minLength;
        }

remove

    // 移除对应下标的元素
	public E remove(int index) {
    	// 检查 index 合法性
        Objects.checkIndex(index, size);
        final Object[] es = elementData;
		// 快速删除
        @SuppressWarnings("unchecked") E oldValue = (E) es[index];
        fastRemove(es, index);

        return oldValue;
    }

    // 移除第一个o
    public boolean remove(Object o) {
        final Object[] es = elementData;
        final int size = this.size;
        int i = 0;
		// 找到第一个o元素的下标
        found: {
        	// o == null  使用 == 
            if (o == null) {
                for (; i < size; i++)
                    if (es[i] == null)
						// 跳回至 found 代码块起始位置 类似于C++的goto语法
                        break found;
            } else {
            // o != null 使用 equals 比较
                for (; i < size; i++)
                    if (o.equals(es[i]))
                        break found;
            }
			// 没有找到删除失败
            return false;
        }
		// 找到元素所在下标 快速删除
        fastRemove(es, i);
        return true;
    }

fastRemove

快速删除

    private void fastRemove(Object[] es, int i) {
    	// 修改次数 + 1
        modCount++;
        final int newSize;
		// 如果要移除的不是最后一个元素
        if ((newSize = size - 1) > i)
			// 将从下标为 i + 1 及以后的所有元素移动到 从 i 开始的位置
            System.arraycopy(es, i + 1, es, i, newSize - i);
		// 如果要移除的是最后一个元素 直接将最后一个元素对应下标的位置设置为null
        es[size = newSize] = null;
    }

clear

清空集合

    public void clear() {
    	// 修改次数 + 1
        modCount++;
        final Object[] es = elementData;
		// 将数组从 0 到 当前元素个数的所有位置全部置为 null
        for (int to = size, i = size = 0; i < to; i++)
            es[i] = null;
    }

addAll

    // 将所有元素全部添加到集合中
    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
		// 修改次数 + 1
        modCount++;
		// 要添加元素的个数
        int numNew = a.length;
        if (numNew == 0)
            return false;
        Object[] elementData;
        final int s;
		// 如果要添加的元素个数 > 当前所剩余容量 进行扩容
        if (numNew > (elementData = this.elementData).length - (s = size))
            elementData = grow(s + numNew);
		// 将要添加的所有元素追加到末尾
        System.arraycopy(a, 0, elementData, s, numNew);
        size = s + numNew;
        return true;
    }

removeRange

    // 移除 fromIndex 到 toIndex 的所有元素
    protected void removeRange(int fromIndex, int toIndex) {
    	// 校验 fromIndex 以及 toIndex 的合法性
        if (fromIndex > toIndex) {
            throw new IndexOutOfBoundsException(
                    outOfBoundsMsg(fromIndex, toIndex));
        }
		// 修改次数 + 1
        modCount++;
		// 擦除 fromIndex 到 toIndex 中间的元素
        shiftTailOverGap(elementData, fromIndex, toIndex);
    }

shiftTailOverGap

    private void shiftTailOverGap(Object[] es, int lo, int hi) {
    	// 从 hi 后面的所有元素复制到 lo开始的位置
        System.arraycopy(es, hi, es, lo, size - hi);
		// 将 hi 后面所有的位置清空
        for (int to = size, i = (size -= hi - lo); i < to; i++)
            es[i] = null;
    }

removeAll

    // 移除参数集合中的所有元素
    public boolean removeAll(Collection<?> c) {
        return batchRemove(c, false, 0, size);
    }

retainAll

    // 取交集
    public boolean retainAll(Collection<?> c) {
        return batchRemove(c, true, 0, size);
    }

batchRemove

	/**
     *在 from 至 end 中间删除/保留 c 中所有存在的元素
     */
    boolean batchRemove(Collection<?> c, boolean complement,
                        final int from, final int end) {
        Objects.requireNonNull(c);
        final Object[] es = elementData;
        int r;
        // Optimize for initial run of survivors
        // complement 为 true 时 from 至 r 中间的所有元素均存在于 c 中
        // complement 为 false 时 from 至 r 中间的所有元素均不存在于 c 中 
        // complement 代表是否要保留
        // 优化性能
        for (r = from;; r++) {
            if (r == end)
                return false;
            if (c.contains(es[r]) != complement)
                break;
        }
		// w 记录要保留的元素个数
        int w = r++;
        try {
			// 
            for (Object e; r < end; r++)
				// 如果对元素要保留将后面的元素向前移动
                if (c.contains(e = es[r]) == complement)
                    es[w++] = e;
        } catch (Throwable ex) {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            System.arraycopy(es, r, es, w, end - r);
            w += end - r;
            throw ex;
        } finally {
			// 修改次数 + 要移除的元素个数
            modCount += end - w;
			// 上面已经将需要保留的元素向前移动  直接擦除 w 及后面的元素
            shiftTailOverGap(es, w, end);
        }
        return true;
    }

contains

返回是否存在对应元素

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

indexOf

    // 返回o在ArrayList中的第一个下标
    public int indexOf(Object o) {
        return indexOfRange(o, 0, size);
    }

indexOfRange

	// 返回 o 在集合的 start 至 end 中第一次出现的下标
    int indexOfRange(Object o, int start, int end) {
        Object[] es = elementData;
		// o == null 比较地址
        if (o == null) {
			// 遍历匹配
            for (int i = start; i < end; i++) {
                if (es[i] == null) {
                    return i;
                }
            }
        } else {
        	// o != null 使用 equals
			// 遍历匹配
            for (int i = start; i < end; i++) {
                if (o.equals(es[i])) {
                    return i;
                }
            }
        }
		// 不存在返回 -1
        return -1;
    }

lastIndexOf

    // 返回 o 在集合中最后一次出现的位置
    public int lastIndexOf(Object o) {
        return lastIndexOfRange(o, 0, size);
    }

lastIndexOfRange

	
	// 返回 o 在集合的 start 至 end 中最后一次出现的下标
	// 与 indexOfRange 处理方式相同 唯一不同是使用倒序遍历
    int lastIndexOfRange(Object o, int start, int end) {
        Object[] es = elementData;
        if (o == null) {
            for (int i = end - 1; i >= start; i--) {
                if (es[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = end - 1; i >= start; i--) {
                if (o.equals(es[i])) {
                    return i;
                }
            }
        }
        return -1;
    }

iterator

返回一个迭代器

    public Iterator<E> iterator() {
        return new Itr();
    }

subList

    // 返回 fromIndex 至 toIndex 中的元素
    public List<E> subList(int fromIndex, int toIndex) {
    	// 参数检查
        subListRangeCheck(fromIndex, toIndex, size);
		// 构造SubList 注意这里并没有复制元素 只是获取了引用
        return new SubList<>(this, fromIndex, toIndex);
    }

内部类Itr(迭代器)

成员属性

    	// 下一个元素的下标
        int cursor;       // index of next element to return
        // 最后一个返回元素的下标 第一次为 -1
        int lastRet = -1; // index of last element returned; -1 if no such
        // 获取集合中当前修改次数 后续有修改操作比较 若不相同则抛出 ConcurrentModificationException 异常
        int expectedModCount = modCount;

主要方法详解

hasNext

        public boolean hasNext() {
        	//下一个元素的下标不等于容量大小则代表没有至末尾 
            return cursor != size;
        }

next

        @SuppressWarnings("unchecked")
        // 返回下一个元素
        public E next() {
        	// 校验 expectedModCount 是否等于 ArrayList 的modCount 不等于则说明迭代器迭代的过程中有在集合中间位置进行修改操作
            checkForComodification();
            int i = cursor;
			// 如果下一个元素的下标大于等于容量说明已经没有元素可以遍历
            if (i >= size)
                throw new NoSuchElementException();
			// 获取外部类的 elementData 即真正存储元素的数组
            Object[] elementData = ArrayList.this.elementData;
			// 如果 i >= 数组长度说明数组长度变短 当前数组已经不是原本的数组
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
			// 设置下一个要遍历元素的下边
            cursor = i + 1;
			// 返回对应下标位置的元素
            return (E) elementData[lastRet = i];
        }

remove

		//通过迭代器删除 
        public void remove() {
        	// 说明当前还未开始遍历元素 或者当前遍历元素已经经历过 remove/add
            if (lastRet < 0)
                throw new IllegalStateException();
			// 校验修改次数
            checkForComodification();

            try {
				// 调用外部类的remove方法
                ArrayList.this.remove(lastRet);
				// 并且将下一个要遍历的下标设置为最后一次返回元素下标  相当于指针向前移动一次
                cursor = lastRet;
                lastRet = -1;
				// 复制 ArrayList 的 modCount 后续的检查不会抛出异常
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

add

		// 通过迭代器进行插入元素
        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
				// 将元素 e 插入到下一个位置
                ArrayList.this.add(i, e);
				// 将遍历指针向后移动
                cursor = i + 1;
                lastRet = -1;
				// 复制 ArrayList 的 modCount 后续的检查不会抛出异常
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }

常见的问题

为什么在forEach循环中使用ArrayList#add 或者 ArrayList#remove方法的话会抛出ConcurrentModificationException异常?

因为forEach其实也是使用迭代器遍历的,add或者remove操作时没有将 modCount 赋值给迭代器的expectedModCount,

为什么ArrayList添加或者删除效率比较低

因为添加可能导致扩容,扩容需要将数组拷贝一份,从中间添加元素需要将后面的元素向后移动,删除同样需要向后移动