ArrayList源码分析

package com.alphamall.collection.list;

import java.io.Serializable;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;

public class LYHArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {

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

    //空元素数组
    private static final Object[] EMPTY_ELEMENTDATA = {};

    //默认大小的空实例数组,在第一次调用 ensureCapacityInternal 时会初始化长度为10
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    //存放元素的数组
    Object[] elementData;

    //集合大小, 初始值为0
    private int size;


    /**
     * Constructs an empty list with the specified initial capacity.
     * 构造一个具有指定初始容量的空列表
     *
     * @param  initialCapacity  列表的初始容量
     * @throws IllegalArgumentException 如果指定的初始容量为负, 抛异常
     */
    public LYHArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            //如果指定的初始容量大于0, 则新new一个object数组
            // 例如 initialCapacity==3, 则 elementData == [null, null, null]
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //如果等于0, 就让elementData=空数组;
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            //否则抛出异常
            throw new IllegalArgumentException("非法的容量异常: " + initialCapacity);
        }
    }

    /**
     * 构造一个初始容量为10的空列表
     */
    public LYHArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }


    /**
     * 传入一个集合, 将这个集合中的数据放到elementData中
     */
    public LYHArrayList(Collection<? extends E> c) {
        //调用该集合的toArray方法, 将数据放入elementData数组中
        elementData = c.toArray();
        //如果此时elementData长度 != 0
        if ((size = elementData.length) != 0) {
            //如果传入的集合c可能不是对象类型的数组, 比如说List<String> list 字符串类型的
            if (elementData.getClass() != Object[].class) {
                //复制一个Object[]类型的数组
                elementData = Arrays.copyOf(elementData, size, Object[].class);
            }
        } else {
            //如果传入的集合是空的, 就直接让 elementData = 空数组
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

    /**
     * 将ArrayList实例的容量调整为列表的当前大小, 使用此操作可以最小化ArrayList实例的存储
     */
    public void trimToSize() {
        //修改列表大小的次数 +1
        modCount++;
        //如果集合的大小 < 元素数组的长度
        if (size < elementData.length) {
            if (size == 0) {
                //elementData = []空数组
                elementData = EMPTY_ELEMENTDATA;
            } else {
                elementData = Arrays.copyOf(elementData, size);
            }
        }
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

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

    public int indexOf(Object o) {
        if (o == null) {
            //如果Object参数的是null, 则找到elementData中包含 null元素的下标
            for (int i = 0; i < size; i++) {
                if (elementData[i] == null) {
                    return i;
                }
            }
        } else {
            //否则比较每一个元素和Object参数是否相等, 相等则返回下标
            for (int i = 0; i < size; i++) {
                if (o.equals(elementData[i])) {
                    return i;
                }
            }
        }
        //没有则返回-1
        return -1;
    }

    public Object clone() {
        try {
            LYHArrayList<?> v = (LYHArrayList<?>) 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);
        }
    }

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


    E elementData(int index) {
        //返回elementData的元素, 并强转为指定类型
        return (E) elementData[index];
    }

    @Override
    public E get(int index) {
        //先检查是否越界
        rangeCheck(index);
        return elementData(index);
    }

    /**
     * 将列表中指定位置的元素替换为指定的元素
     */
    public E set(int index, E element) {
        rangeCheck(index);

        //获取index位置对应的旧值
        E oldValue = elementData(index);
        //给index位置赋新值
        elementData[index] = element;

        return oldValue;
    }

    /**
     * 将指定的元素追加到列表的末尾, 即elementData[size]的位置
     */
    public boolean add(E e) {
        //确定是否需要扩容
        ensureCapacityInternal(size + 1);  //增加 modCount修改次数的大小

        //将元素e 赋值给 elementData[size], 然后size自增
        // 这里如果是多线程的情况下会不安全, 假设 t1和 t2线程都执行到这一步, 会给 elementData[size]赋值,
        // 然后size再++, 相当于只新增了一个元素
        // 例如  elementData == [1,2,3,null], 此时size=3, t1线程给elementData[3]赋值 4, 但size还没来得及自增
        // t2线程又给 elementData[3]的位置 赋值5, 最后就可能会导致, elementData == [1,2,3,5], 4没有加上
        // 但 size却 ++ 2次, 即size==5
        elementData[size++] = e;
        return true;
    }

    /**
     * 在列表的指定位置插入指定的元素。将当前在该位置的元素(如果有的话)和任何后续元素向右移动(在它们的下标上加1)
     * 例如: elementData == [1,2,3,4,5,6,7,8,null,null] (elementData.length==10) 插入数字100以后 --->
     *       elementData == [1,2,3,4,100,5,6,7,8,null,null,null,null,null,null] 会伴随着扩容 (elementData.length==15)
     * @param index 下标
     * @param element 要新增的元素
     */
    public void add(int index, E element) {
        //判断index是否越界
        rangeCheckForAdd(index);
        //判断是否需要扩容
        ensureCapacityInternal(size + 1);
        /**
         * 把数组的中间某一段, 复制到数组的另一段上
         * 例如: [1, 2, 3, 4, 5, null, null] 中间的 [3,4,5] 复制到 [4,5,null] 的位置 ===> [1,2,3,3,4,5,null]
         * @param      src      原数组
         * @param      srcPos   要复制的某一段的起始位置
         * @param      dest     目标数组
         * @param      destPos  复制到目标位置
         * @param      length   要复制的数组长度
         */
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
        //给index位置赋值 element
        elementData[index] = element;
        size++;
    }

    /**
     * 移除列表中指定位置的元素。将所有后续元素向左移动(从其下标中减去1)
     */
    public E remove(int index) {
        //判断index是否越界, 即须要 index < size
        rangeCheck(index);

        modCount++;
        //获取指定位置的元素
        E oldValue = this.elementData(index);

        //例如 elementData == [1,2,3,4,5]  index==2  --> numMoved==2
        int numMoved = size - index - 1;  //numMoved: 要移动元素的数量
        if (numMoved > 0) {
            //elementData从 elementData[3]这个位置开始复制, 复制2个元素, 到elementData[2]这个位置
            // 即 elementData == [1,2,3,4,5] --> elementData == [1,2,4,5,5]
            System.arraycopy(elementData, index + 1, elementData, index, numMoved);
        }
        //先让 size-1 == 4, 再让elementData[4] == null, elementData == [1,2,4,5,null]
        elementData[--size] = null;

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

    /**
     * 从列表中删除指定元素的第一个出现项(如果它存在的话)
     * @param o
     * @return
     */
    public boolean remove(Object o) {
        //先判断参数 o 是否为空
        if (o == null) {
            for (int i = 0; i < size; i++) {
                if (elementData[i] == null) {
                    //移除第一次出现的空元素
                    fastRemove(i);
                    return true;
                }
            }
        } else {
            for (int i = 0; i < size; i++) {
                if (o.equals(elementData[i])) {
                    //移除第一次出现的值相等元素
                    fastRemove(i);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 和 remove(int index) 方法类似
     */
    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;
    }

    /**
     * 从列表中删除所有元素。此调用返回后,列表将为空
     */
    public void clear() {
        modCount++;
        for (int i = 0; i < size; i++)
            elementData[i] = null;
        size = 0;
    }

    /**
     * 将指定集合中的所有元素追加到列表的末尾
     * 例如: c==[6,7,8] length==3   elementData==[1,2,3,4,5,null]  elementData.length==6
     */
    public boolean addAll(Collection<? extends E> c) {
        // objects==[6,7,8]
        Object[] objects = c.toArray();
        int length = objects.length;

        //扩容 --> elementData==[1,2,3,4,5,null,null,null,null]  elementData.length==6+3==9
        ensureCapacityInternal(size + length);

        //将[6,7,8]复制到 elementData[5]后面, 以index==5为起点 ---> elementData==[1,2,3,4,5,6,7,8,null]
        System.arraycopy(objects, 0, elementData, size, length);

        //这个时候 size==8
        size += length;

        return length != 0;
    }

    /**
     * 从指定位置开始,将指定集合中的所有元素插入到此列表中
     * 例如: c==[6,7,8]  index=2  elementData==[1,2,3,4,5,null]
     */
    public boolean addAll(int index, Collection<? extends E> c) {
        //先检查 index 是否在 (0,size)这个区间中
        rangeCheckForAdd(index);

        // >>> objects==[6,7,8]
        Object[] objects = c.toArray();
        int length = objects.length;

        //扩容 >>> elementData==[1,2,3,4,5,null,null,null,null] elementData.length==9
        ensureCapacityInternal(size + length);

        // 要移动的元素个数: 设最后一个元素的下标为 last, 从index下标开始,
        // 则移动的元素个数为 last-index+1 == (last+1)-index == size-index
        // >>> numMoved==5-2==3
        int numMoved = size - index;

        /*这里如果index==size, 那 numMoved==0, 就直接把 objects拼接到 size后面, 以size为起点*/
        if (numMoved > 0) {
            //从3复制到6的位置 >>> elementData==[1,2,null,null,null,3,4,5]
            System.arraycopy(elementData, index, elementData, index + length, numMoved);
        }
        //再将 objects复制到3的位置 >>> elementData==[1,2,6,7,8,3,4,5]
        System.arraycopy(objects, 0, elementData, index, length);

        return true;
    }

    /**
     * 从该列表中移除包含在指定集合中的所有元素
     */
    public boolean removeAll(Collection<?> c) {
        //检查指定的对象引用不是null
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }

    /**
     * 从这个列表中删除指定集合中不包含的所有元素
     */
    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }

    /**
     * 批量移动, 把参数集合中不包含或包含的元素, 移动到数组前面
     * 例如: elementData==[1,2,3,4,5,6,7]  c==[1,3,6]  complement==false
     * >>> 移动后: elementData==[2,4,5,7,5,6,7]
     */
    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++) {
                //判断c中是否包含elementData 的第r个元素, 不包含就把当前元素放到前面, w每次+1
                if (c.contains(elementData[r]) == complement) {
                    // r==0 elementData==[1,2,3,4,5,6,7]  w==0
                    // r==1 elementData==[2,2,3,4,5,6,7]  w==1
                    // r==2 elementData==[2,2,3,4,5,6,7]  w==1
                    // r==3 elementData==[2,4,3,4,5,6,7]  w==2
                    // r==4 elementData==[2,4,5,4,5,6,7]  w==3
                    // r==5 elementData==[2,4,5,4,5,6,7]  w==3
                    // r==6 elementData==[2,4,5,7,5,6,7]  w==4
                    elementData[w++] = elementData[r];
                }
            }
        } finally {
            //r==7 size==7
            if (r != size) {
                System.arraycopy(elementData, r, elementData, w, size - r);
                w += size - r;
            }

            //这一步就是将 elementData向前移动的元素保留下来, 其他的置为空
            if (w != size) {  //w==4
                //elementData==[2,4,5,7,null,null,null]
                for (int i = w; i < size; i++) {
                    elementData[i] = null;
                }
                // modCount += 7-4==3
                modCount += size - w;
                size = w;  //size==4
                modified = true;
            }
        }
        return modified;
    }

    /**
     * 遍历集合
     */
    @Override
    public void forEach(Consumer<? super E> action) {
        //action不为空
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;

        // elementData[i]作为参数, 执行 action方法, 也就是自己的lambda表达式
        for (int i = 0; i < size && modCount == expectedModCount; i++) {
            action.accept(elementData[i]);
        }
        //在遍历的时候, arrayList中途不能修改
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException("并发修改异常");
        }
    }

    /**
     * 对每一个参数进行修改或替换操作
     *    arrayList==[1, 2, 3, 4, 5, 6, 7]
     *    arrayList.replaceAll(s -> {
     *         Integer integer = Integer.valueOf(s);
     *         return integer + 1 + "";
     *    });
     *    >>> arrayList==[1, 2, 3, 4, 5, 6, 7, 8]
     * @param operator
     */
    @Override
    public void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final int expectedModCount = modCount;
        final int size = this.size;

        for (int i = 0; i < size && modCount == expectedModCount; i++) {
            //对每个元素进行一元运算操作, 返回的是和参数相同的类型
            elementData[i] = operator.apply((E) elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

    /**
     * 给list按照Comparator指定的规则排序
     * @param c
     */
    @Override
    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++;
    }


    /**
     * 删除该集合中满足给定断言条件的所有元素
     * 例如 arrayList==[1, 2, 3, 4, 5, 6, 7]   filter: s -> Integer.parseInt(s) > 3
     * 删除比3大的所有元素
     */
    @Override
    public boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);

        int removeCount = 0;
        final BitSet removeSet = new BitSet(size);  // removeSet=={}
        final int expectedModCount = modCount;
        final int size = this.size;  //size==7

        for (int i=0; modCount == expectedModCount && i < size; i++) {
            @SuppressWarnings("unchecked")
            final E element = (E) elementData[i];
            if (filter.test(element)) {
                removeSet.set(i);  //满足条件的元素下标放入 removeSet=={3,4,5,6}
                removeCount++;  //removeCount==4  要删除的元素数量是4个
            }
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }

        final boolean anyToRemove = removeCount > 0;  //removeCount==4
        if (anyToRemove) {
            final int newSize = size - removeCount;  //size==7  removeCount==4  newSize==3
            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
                i = removeSet.nextClearBit(i);
                elementData[j] = elementData[i];
            }
            // >>>> 真正删除是从这一步开始的
            // elementData==[1, 2, 3, 4, 5, 6, 7]  >>> elementData==[1,2,3,null,null,null.null]
            for (int k=newSize; k < size; k++) {
                elementData[k] = null;  //将下标从3到6的位置的元素为null
            }
            this.size = newSize;  //size==3
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
            modCount++;
        }

        return anyToRemove;
    }

    /**
     * 确定容量大小, 是否需要扩容
     * ===> 一般,初始化 new ArrayList<>();没有指定容量, 第一次add就会扩容到10
     * @param minCapacity 最小容量
     */
    private void ensureCapacityInternal(int minCapacity) {
        //如果elementData == [], 即 new ArrayList<>()的时候, 没指定初始容量 initialCapacity, 会让 minCapacity = 10
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //获取 (size+1) 和 10的较大者, 这里elementData是等于空数组了, 那size+1等于1是肯定比 10 要小的,
            //为什么还要获取两者之间的最大值呢? 直接把 10 赋给 minCapacity不行吗 ???
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }

    /**
     * 判断elementData是否已经装满了, 就是判断需要的容量 是否大于 elementData的长度
     * 例如: elementData == [1,2,3,null],add一个元素,就不需要扩容, 如果elementData == [1,2,3,4], 就需要扩容
     */
    private void ensureExplicitCapacity(int minCapacity) {
        //修改次数+1
        modCount++;

        //在add的时候, 判断时候需要扩容, 如果需要的最小容量即 (size+1) > elementData长度
        if (minCapacity - elementData.length > 0) {
            //例如list初始化指定的initialCapacity是3 【调用的是构造方法 public LYHArrayList(int initialCapacity)】
            //此时elementData = new Object[3], elementData.length == 3; 也就是[null, null, null],
            //在每次add元素的时候, 前三次走到这里判断 (size+1) 都是 <= 3的, 也就是不需要扩容, 当第四次add元素的时候,
            //判断 size+1 == 4, 此时 4 > 3, 就走 grow 进行扩容
            grow(minCapacity);
        }
    }

    //数组允许的最大长度
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 增加容量,以确保它至少能容纳由最小容量参数指定的元素数量
     * @param minCapacity 期望的最小容量
     */
    private void grow(int minCapacity) {
        //获取旧容量
        int oldCapacity = elementData.length;
        //new = old + old/2, 扩容为原来的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);

        //如果新容量 < 最小容量
        if (newCapacity - minCapacity < 0) {
            // 能走到这里, 有两种情况
            // 1. elementData等于空数组[], 此时 minCapacity = DEFAULT_CAPACITY==10
            //    oldCapacity==0 --> newCapacity==0 --> 0<10 则让 newCapacity = minCapacity==10
            // 2. 可能是一开始构造方法指定 initialCapacity==1
            //    比如 elementData == [1], elementData.length==1 --> oldCapacity==1 --> newCapacity==1,
            //    而此时 minCapacity == size+1 == 2, minCapacity(2) > newCapacity(1), newCapacity会重新赋值为 2
            newCapacity = minCapacity;
        }
        //新容量 > 最大数组容量
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            newCapacity = hugeCapacity(minCapacity);
        }

        //elementData复制新容量的数组, 再赋值给 elementData (例如[1,2,3] ===> [1,2,3,null])
        elementData = Arrays.copyOf(elementData, newCapacity);
    }


    //最大的容量
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) { // overflow
            throw new OutOfMemoryError();
        }

        //如果最小容量 > Integer.MAX_VALUE - 8
        if (minCapacity > MAX_ARRAY_SIZE) {
            //返回 2的31次方 -1
            return Integer.MAX_VALUE;
        } else {
            //返回 2的31次方 -9
            return MAX_ARRAY_SIZE;
        }
    }

    /**
     * 判断 index是否越界, 必须 0 <= index <= size
     * ===> 给 add and addAll 使用的方法
     */
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /**
     * 检查给定的索引是否在范围内。如果不是,则抛出适当的运行时异常。
     * 此方法不检查索引是否为负:它总是在数组访问之前立即使用,如果索引为负,将抛出ArrayIndexOutOfBoundsException
     */
    private void rangeCheck(int index) {
        if (index >= size) {
            //下标越界异常
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    }

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值