ArrayList源码阅读分析

86 阅读10分钟

ArrayList

Java中最常用的集合类,一个可自动扩容的对象数组,默认是一个对象数组,并且每次扩容都是1.5倍旧容量(通过右移位来代替 / 2,从而提升速度 + 原本容量就是1.5倍原容量),但是它不是一个线程安全的类

new

默认情况下数组为一个空数组,通过无参构造新建

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

当然也可以指定数组初始化大小,你传入的容量大小,如果为0则用ArrayList自带的,否则new 一个Object[你传入的容量大小]的对象数组

private static final Object[] EMPTY_ELEMENTDATA = {};

public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) { // 传入的的大小 > 0,则用你传入的大小
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {// 如果为为0的话,就用ArrayList自带的一个空数组
        this.elementData = EMPTY_ELEMENTDATA;
    } else { // 其他则抛出异常
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

resize

ArrayList的添加并不是线程安全的,每一次添加都会size + 1用来去判定是否容量已经超过数组的容量了,如果超过了则扩容。没有则直接添加数据,最终返回true

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

ensureCapacityInternal 判定数组容量中,会去先计算容量大小,如果这个容量大于当前数组容量的长度则进行扩容。前面new的一个空ArrayList在第一个添加数组时就会在这里进行初始化成一个容量大小为10的数组对象

private void ensureCapacityInternal(int minCapacity) { // 这个 minCapacity 是当前数组容量 size + 1 后的值
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // 判断当前数组对象是否是ArrayList默认的对象数组,如果是,则将默认数组容量大小 10 与现在当前数组 size + 1 进行比较,最终返回较大的数;如果不是则直接返回 size + 1
        return Math.max(DEFAULT_CAPACITY, minCapacity); 
    }
    return minCapacity;
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0) // 判定最小容量,是否超过数组的长度 (第一次 10 - 0 > 0 进行扩容,否则直接跳过)
        grow(minCapacity);
}

overflows[扩容溢出问题]

对于计算机中的溢出数字看起来像一个圆环,对于一个数字溢出的数字一直 + 的话,最终会变成一个正数->溢出->正数.....

image-20230808121910960转存失败,建议直接上传图片文件

image-20230808122302140转存失败,建议直接上传图片文件

grow

调用grow容量进行扩容,其中容量扩容是旧容量的1.5倍,如果新的容量大小还比旧的容量大小的话,那么就用旧的容量大小,比如第一次初始化 minCapacity 为 10,但是 newCapacity 为 0 ,就产生了这种情况,然后是对溢出的判定,假如 minCapacity 已经是 Integer.MAX_VALUE + 1 此时已经溢出了,然后去减去 MAX_ARRAY_SIZE,如果按照正常数学算数 负数 - 一个数 = 负数,但是计算机中对于这种溢出的相减不一样,这里会是一个不为负数的数。hugeCapacity 方法判定要么抛出OOM,要么返回Integer的最大值,最终进行数组复制。

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

// 扩容
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length; // 旧的容量大小
    int newCapacity = oldCapacity + (oldCapacity >> 1); // 新的容量大小等于(旧的容量大小 + 旧的容量大小 / 2)或者就是( 1.5倍 旧容量大小)
    if (newCapacity - minCapacity < 0) // 新容量还比就容量小,就还是用旧的 (什么情况下能进入呢?第一次扩容会出现,我的minCapacity == 10, 但是newCapacity = oldCapacity + (oldCapacity >> 1) 算出来是等于 0 的于是就出现了旧容量比容量大的情况)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0) // 如果新容量比 MAX_ARRAY_SIZE()还要大的话,进行再次容量变更,此时有可能已经溢出了
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity); // 开始复制旧数组到一个新容量的数组上,最后将新数组赋值给 elementData
}

// 大容量判定赋值
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // 如果容量都为负数了,则表示overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ? // 如果都超过 MAX_ARRAY_SIZE( Integer.MAX_VALUE - 8)了,就直接返回 Integer 的最大值
        Integer.MAX_VALUE :
    MAX_ARRAY_SIZE;
}

get

public E get(int index) {
   	// 判定index是否大于等于list长度
    rangeCheck(index);
	// 返回数据
    return elementData(index);
}

private void rangeCheck(int index) {
    // 大于抛下标越界异常
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

E elementData(int index) {
	// 返回elementData的index下标的数据
    return (E) elementData[index];
}

remove

// 通过下标移出数据
public E remove(int index) {
    // 上面get中的rangeCheck方法,判定传入的index是否越界
    rangeCheck(index);
	// 修改次数++
    modCount++;
    // 下标为index的值,先保存,remove掉后再返回
    E oldValue = elementData(index);
	// 算出需要移动的元素个数
	// index 后面的数向前移动
    // 1 2 3 4 5 (移出下标为2的数字3,此时4和5需要向前移动)5 - 2 - 1 = 2
    // 1 2 4 5
    int numMoved = size - index - 1;
    if (numMoved > 0)
        // 复制后面的数据
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    // 末尾设置为null
    elementData[--size] = null; // clear to let GC do its work 设置null,以便gc回收
	// 返回旧数据
    return oldValue;
}

// 通过传入数据
public boolean remove(Object o) {
    // 如果传入null,会去elementData数组里面去找是否有null的,会将所有null给清除掉
    if (o == null) {
        // 遍历elementData
        for (int index = 0; index < size; index++)
            // 是否找到null
            if (elementData[index] == null) {
                // 快速移出 null,并将数据前移
                fastRemove(index);
                return true;
            }
    } else {
        // 遍历elementData
        for (int index = 0; index < size; index++)
            // 是否找到o
            if (o.equals(elementData[index])) {
                // 快速移出
                fastRemove(index);
                return true;
            }
    }
    return false;
}

private void fastRemove(int index) {
    modCount++;
    // 求出index后的数据个数
    int numMoved = size - index - 1;
    if (numMoved > 0)
        // index后的数据前移
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    // 末尾设置为null,方便gc
    elementData[--size] = null; // clear to let GC do its work
}

clone

// 重写了clone方法
public Object clone() {
    try {
        // 调用父类Object的clone
        ArrayList<?> v = (ArrayList<?>) super.clone();
        // 复制原elementData的数据
        // 并且挂载到v上
        v.elementData = Arrays.copyOf(elementData, size);
        // 初始化modCount
        v.modCount = 0;
        // 返回
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

size

public int size() {
    // size
    return size;
}

contains

public boolean contains(Object o) {
    // 如果返回为-1表示为包含,否则包含
    return indexOf(o) >= 0;
}

public int indexOf(Object o) {
    // 添加if else 判定可以防止下面空指针异常
   	// 两个都是for循环到结尾,对于null用==来判定,对于非null用equals来判定
    // 只会返回找到的第一个
    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;
}

toArray

// 返回一个复制的数组
public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}

// 传入一个数组,用来装elementData
public <T> T[] toArray(T[] a) {
    // 如果传入的数组长度小于 elementData 的长度
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
	   // 返回一个新的数组 
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    // 将elementData 装进a里
    System.arraycopy(elementData, 0, a, 0, size);
    // a 末尾设置null,用于标记,表名此处为一个分界点,防止拿到一些原数组的数据,让复制的数据更加安全
    if (a.length > size)
        a[size] = null;
    return a;
}

clear

public void clear() {
    modCount++;

    // clear to let GC do its work
    // 全部设置成null,让gc回收
    for (int i = 0; i < size; i++)
        elementData[i] = null;
	// 重置size
    size = 0;
}

addAll

// 将传入的集合
// 追加数据
public boolean addAll(Collection<? extends E> c) {
    // 转成对象数组
    Object[] a = c.toArray();
    // 保存a长度
    int numNew = a.length;
    // 是否需要扩容
    ensureCapacityInternal(size + numNew);  // Increments modCount
    // 将数组复制追加到elementData尾部
    System.arraycopy(a, 0, elementData, size, numNew);
    // 更新size
    size += numNew;
    // 传入集合长度不为0表示成功
    return numNew != 0;
}

// 插入数据
// 有下标的,将index下表开始移动到index + 集合的长度(将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开始的数据向后移动,从index + numNew开始
        System.arraycopy(elementData, index, elementData, index + numNew,
                         numMoved);
	// 插入新数据
    System.arraycopy(a, 0, elementData, index, numNew);
    // 更新size
    size += numNew;
 	// 返回是否添加成功
    return numNew != 0;
}

removeAll

// 批量remove, 删除传入的集合
public boolean removeAll(Collection<?> c) {
    // 非空判定
    Objects.requireNonNull(c);
	// false 表示 c 是否包含elementData[n] == false (0 < n < size)
    return batchRemove(c, false);
}

private boolean batchRemove(Collection<?> c, boolean complement) {
    // 临时elementData
    final Object[] elementData = this.elementData;
    // 初始化两个下标
    int r = 0, w = 0;
    // 是否修改过
    boolean modified = false;
    try {
        // 遍历elementData
        for (; r < size; r++)
            // 利用传入集合c,来判定是否elementData中的数据
            // complement == false 表示只保留c中没有的,移出c中有的
            // complement == true 表示只保留c中有的,移出c中没有的
            if (c.contains(elementData[r]) == complement)
                // 通过遍历elementData,然后将需要保留的数据再次存入到elementData中,但是可能会遗留一些数据
                elementData[w++] = elementData[r];
    } finally {
        // Preserve behavioral compatibility with AbstractCollection,
        // even if c.contains() throws.
        // 防止抛异常,导致数据不一致
        // r != size 表示没有遍历完elementData
        if (r != size) {
            // r 异常发生下标,将r及r后的数据追加到w后,后面那些数据是没有进行判定的
            System.arraycopy(elementData, r,
                             elementData, w,
                             size - r);
            // 更新w
            w += size - r;
        }
        // 从w开始,进行清理数据(将数据设置成null)
        if (w != size) {
            // clear to let GC do its work
            // 遍历
            for (int i = w; i < size; i++)
                // 数据设置成null
                elementData[i] = null;
            modCount += size - w;
            size = w;
            // remove成功
            modified = true;
        }
    }
    return modified;
}

retainAll

// 批量remove,保留传入的集合
public boolean removeAll(Collection<?> c) {
    // 非空判定
    Objects.requireNonNull(c);
    // 与上面类似,但是complement是false
    return batchRemove(c, false);
}

subList

public List<E> subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size);
    // 返回一个 SubList对象,操作这个对象会对原elementData产生影响
    return new SubList(this, 0, fromIndex, 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;
    }
    ...
}

forEach

public void forEach(Consumer<? super E> action) {
	// 非空判定
    Objects.requireNonNull(action);
    // 保存修改次数
    final int expectedModCount = modCount;
    @SuppressWarnings("unchecked")
    // 临时保存
    final E[] elementData = (E[]) this.elementData;
    // 临时size
    final int size = this.size;
    // 遍历,如果有其他线程修改,会抛出并发修改异常
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        // 调用Consumer的accept方法
        action.accept(elementData[i]);
    }
    // 修改次数不一致,抛出异常
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

removeIf

public boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);
    // figure out which elements are to be removed
    // any exception thrown from the filter predicate at this stage
    // will leave the collection unmodified
    int removeCount = 0;
    // 通过BitSet来记录需要移出数据的下标
    final BitSet removeSet = new BitSet(size);
    // 修改次数
    final int expectedModCount = modCount;
    // 原elementData容量大小
    final int size = this.size;
	// 开始遍历,modCount == expectedModCount 防止并发修改
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        @SuppressWarnings("unchecked")
        final E element = (E) elementData[i];
    	// 是否满足test
        if (filter.test(element)) {
            // 保存移出下标
            removeSet.set(i);
            removeCount++;
        }
    }
    // 是否被修改过
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }

    // shift surviving elements left over the spaces left by removed elements
    // 判定是否被修改过
    final boolean anyToRemove = removeCount > 0;
    if (anyToRemove) {
        // 新size大小
        final int newSize = size - removeCount;
        // 遍历
        for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
            // 获取下标
            i = removeSet.nextClearBit(i);
            // 覆盖数据
            elementData[j] = elementData[i];
        }
        // 清除多余的数据
        for (int k=newSize; k < size; k++) {
            elementData[k] = null;  // Let gc do its work
        }
        // 重新设置size
        this.size = newSize;
        // 判定修改异常
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

    return anyToRemove;
}

replaceAll

// 替换所有数据
public void replaceAll(UnaryOperator<E> operator) {
    // 非空判定
    Objects.requireNonNull(operator);
    // 临时变量 修改次数
    final int expectedModCount = modCount;
    // 临时变量 size
    final int size = this.size;
    // 遍历 + 修改,对原来数据进行加工
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        elementData[i] = operator.apply((E) elementData[i]);
    }
    // 修改次数不一致,抛出异常
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    modCount++;
}

sort

@SuppressWarnings("unchecked")
public void sort(Comparator<? super E> c) {
    final int expectedModCount = modCount;
    // 排序(合并排序TimSort)
    Arrays.sort((E[]) elementData, 0, size, c);
    // 防止排序中被其他线程修改
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    modCount++;
}

trimToSize

// 对elementData进行瘦身
public void trimToSize() {
    modCount++;
    // size < elementData的length
    if (size < elementData.length) {
        // size 是否为0,对elementData 是赋值空对象数组 EMPTY_ELEMENTDATA,还是再复制一份size 大小的 elementData
        elementData = (size == 0)
            // 空对象数组
            ? EMPTY_ELEMENTDATA
            // 赋值一份elementData的数据
            : Arrays.copyOf(elementData, size);
    }
}