先作总结

  1. 底层基于数组实现,物理储存是连续的。查询修改速度快,增删慢。
  2. ArrayList的容量可以随着元素的增加而自动增加,每次扩容为约原数组容量的1.5倍,因此不用担心ArrayList容量不足的问题。
  3. ArrayList是非线程安全的。
  4. 可储存多个null。
  5. 覆盖了函数clone(),能被克隆。

 属性:

private static final int DEFAULT_CAPACITY = 10;  // 初始容量
private static final Object[] EMPTY_ELEMENTDATA = {};  // 空数组-->传容量为0时定义的
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};  // 不传容量时,初始值
transient Object[] elementData; // 数组实现
private int size;  // 数组实际大小

构造器

三个构造器:1、传容量大小 2、不传容量 3、传一个collection

自动扩容

int newCapacity = oldCapacity + (oldCapacity >> 1);

如果容量超过了数组的capacity,那么就扩到约原来的1.5倍。

注意:

        当我们用无参构造方法创建的数组,ArrayList初始容量为0(DEFAULTCAPACITY),添加一个元素后容量就变为10了。

        当使用有参构造方法或集合构造方法初始化为0,添加元素前,初始容量为0,添加一个元素后容量变为1.

主要方法

1. 添加

public boolean add(E e);
public void add(int index, E element);
public boolean addAll(Collection<? extends E> c);
public boolean addAll(int index, Collection<? extends E> c);

主要流程:

                1.判断下标是否越界

                2.判断插入后大小是否大于数组的长度,长了则扩容grow()-->(拷贝到新的数组)读写分离操作

                3.插入数组

2. 更新

public E set(int index, E element) {
    rangeCheck(index);//下标越界检查
    E oldValue = elementData(index);
    elementData[index] = element;//赋值到指定位置,复制的仅仅是引用
    return oldValue;
}

3. 查找

public E get(int index) {
    rangeCheck(index);
    return (E) elementData[index];//注意类型转换
}
public int indexOf(Object o); //  查找第一次出现的位置
public int lastIndexOf(Object o);  // 查找最后一次出现的位置

4. 删除

        删除指定位置

public E remove(int index) {
    rangeCheck(index);
    modCount++;
    E oldValue = elementData(index);
    int numMoved = size - index - 1;
    if (numMoved > 0)  // 判断是否为最后一个值,将index+1及后的移动到index及子后
        System.arraycopy(elementData, index+1, elementData, index, numMoved);
    elementData[--size] = null; //清除该位置的引用,让GC起作用
    return oldValue;
}

        删除指定对象

public boolean remove(Object o) {
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

5. 更新数组的实际大小

        将底层数组的容量调整为当前列表保存的实际元素的大小

public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}

Fail-Fast机制:

ArrayList也采用了快速失败的机制,通过记录modCount参数来实现。在面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。