一、扩容

    1. 初始容量

    image.png
    调用ArrayList无参构造创建时,初始容量为0,往数组里添加元素,变成10。

    1. 之后扩容

    1)调用add方法
    ArrayList扩容,调用grow方法,原来的数组长度右移一位,容量是之前的1.5倍。
    将旧数组copy到扩容后的新数组里,旧数组没有地方引用,会被垃圾回收。
    image.png
    image.png
    2)调用addAll方法
    一次扩容到位(在1.5倍扩容和addAll实际对象的size之间选一个较大的值)
    image.png
    总结:
    ArrayList()会使用长度为0的数组;
    ArrayList(int initialCapacity)会使用指定容量的数组;
    public ArrayList(Collection<?extendsE> c)会使用c的大小作为数组容量;
    add(Object o)首次扩容为10,再次扩容为上次容量的1.5倍;
    addAll(Collection c)没有元素时,扩容为Math.max(10,实际元素个数),有元素时为Math.max(原容量1.5倍,实际元素个数)。

    二、迭代器

    1. fail-fast (ArrayList)

      一旦发现遍历的同时有其他人来修改,则立刻抛出异常。
      image.png
      遍历时,调用next()方法,通过判断循环开始时modCount和循环进行中的expectedModCount,list修改次数是否一致,来抛异常。

    2. fail-safe (CopyOnWriteArrayList)

    发现遍历的同时其他人来修改,应当能有应对策略,例如牺牲一致性来让整个遍历运行完成(遍历到的不是最新的元素)。
    遍历数组时,先拷贝一份旧数组,再对旧数组进行遍历。
    添加元素时,每次都复制一个旧数组,并+1,将添加的元素塞到最后一个,再赋值给旧数组。
    image.png
    调用迭代器的remove方法不会抛异常,因为它修改了expectedModCount为最新值。