一、ArrayList的注意事项:

1)ArrayList可以放任何元素,包括空值,可以加入多个空值。
2)ArrayList是由数组来实现数据存储的
3)ArrayList基本等同于Vector,除lArrayList是线程不安全(执行效率高),在多线程情况下,不建议使用ArrayList
没有synchronized进行修饰

二、ArrayList 的底层操作机制源码分析(重点,难点)

  • ArrayList 中维护了一个 Object类型的数组 elementData。 transient Object[]
    elementData; // transient 标识瞬间,短暂的,表示该属性不会被序列化
  • 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData
    容量为0,第一次添加,则扩容elementData为10,如需再次扩容,则扩容elementData为1.5倍。
  • 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。
// 关闭警告
@SuppressWarnings({"all"})
public class ArrayListSource {
    public static void main(String[] args) {

//      源码分析
//      使用无参构造器创建ArrayList对象
        ArrayList list = new ArrayList();
//      使用for循环给list集合添加 1-10 数据
        for (int i = 0; i <= 10; i++) {
            list.add(i);
        }
//      使用for循环给list集合添加 11-15 数据
        for (int i = 11; i<=15;i++){
            list.add(i);
        }
        list.add(100);
        list.add(200);
        list.add(null);
        
        for (Object o : list) {
            System.out.println(o);
        }
    }
}
  • 在 ArrayList list = new ArrayList(); 处添加断点
  • debug – step Into 到 ArrayList.java的ArrarList()构造方法
  • 使用无参构造器
/**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
  • 查询DEFAULTCAPACITY_EMPTY_ELEMENTDATA可发现 默认为空数组
/**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

然后执行 list 的boolean add(E e)方法
先确定是否要扩容,
然后再执行 赋值

/**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

在boolean add(E e)方法中,先执行ensureCapacityInternal(size + 1)方法确定是否要扩容,然后再执行赋值。

private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

在calculateCapacity()方法中 先确定elementData是否为空数组,如果为空数组,返回DEFAULT_CAPACITY(默认为10) 和 minCapacity(第一次为1) 中的最大值,

private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

在ensureExplicitCapacity(int minCapacity)方法中确定是否真的扩容

modCount++ :记录集合修改次数
如果elementData大小不够,则调用grow()进行扩容

minCapacity - elementData.length > 0 :如果数组所需最小容量 - 数组当前实际大小 大于 0 则执行扩容

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

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

grow()方法执行扩容

  • 将elementData.length 记录到 oldCapacity中,第一次值为0 newCapacity = oldCapacity
  • (oldCapacity >> 1); 执行扩容,扩容大小为 数组当前容量+数组当前大小右移1位(除以2),即扩容1.5倍
  • 因为第一次扩容oldCapacity 为0 所有newCapacity 也为0,执行 if (newCapacity -
    minCapacity < 0) newCapacity = minCapacity; 此时newCapacity 为
    10,所以第一次扩容大小为 10
  • elementData = Arrays.copyOf(elementData, newCapacity);
    Arrays.copyOf()方法可保留原先数据扩容 执行Arrays.copyOf()方法进行扩容,第一次执行完elementData
    中有10个空数据
/**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

扩容完成后,继续执行add()方法,将数据添加到elementData数组中