先作总结:
底层基于数组实现,物理储存是连续的。查询修改速度快,增删慢。
ArrayList的容量可以随着元素的增加而自动增加,每次扩容为约原数组容量的1.5倍,因此不用担心ArrayList容量不足的问题。
ArrayList是非线程安全的。
可储存多个null。
覆盖了函数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参数来实现。在面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。