1.2.1 底层结构
底层transient Object[] elementData动态数组,实现RandomAccess标记接口,标记支持随机访问,for 循环遍历性能远高于迭代器。核心字段:
java
private static final int DEFAULT_CAPACITY = 10; // 默认初始容量
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 无参构造空数组
private static final Object[] EMPTY_ELEMENTDATA = {}; // 指定0容量空数组
transient Object[] elementData; // 存储元素数组,transient不序列化
private int size; // 当前存储元素数量
protected transient int modCount; // 修改计数,快速失败
文字解释
- 无参构造不会直接创建长度 10 数组,延迟初始化,首次 add 才扩容,节省内存;
- transient:序列化时跳过数组,writeObject 手动序列化元素,过滤空元素节省空间。
1.2.2 三大构造方法注释
arduino
// 无参构造,赋值空延迟数组,首次add扩容至10
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// 指定初始容量
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
// 大于0创建对应长度数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 0容量赋值空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 负数抛非法参数异常
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
}
}
// 传入集合初始化ArrayList
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// 部分集合toArray返回非Object数组,强制转换
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 传入空集合,赋值空数组
this.elementData = EMPTY_ELEMENTDATA;
}
}
1.2.3 add () 扩容完整源码注释
scss
public boolean add(E e) {
// 校验容量,不足则扩容
ensureCapacityInternal(size + 1);
elementData[size++] = e; // 尾部存入元素,size自增
return true;
}
// 计算所需最小容量
private void ensureCapacityInternal(int minCapacity) {
// 判断是否是无参构造的空数组,首次add最小容量取10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++; // 修改计数+1
// 所需容量超过数组长度,执行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
// 扩容核心方法
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容1.5倍
// 新容量仍不足,直接使用最小需要容量
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 超过最大数组长度,赋值最大限制
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 数组拷贝,开辟新内存,复制旧数组全部元素
elementData = Arrays.copyOf(elementData, newCapacity);
}
文字扩容解释
- 无参 ArrayList 是空数组,第一次 add 扩容至 10;
- 每次扩容原数组 1.5 倍,通过
Arrays.copyOf复制全部元素,拷贝开销大; - 大批量 add 前调用
list.ensureCapacity(预估数量),减少多次拷贝。
1.2.4 各操作时间复杂度
- get (index) /set (index,E):O (1) 随机访问,数组下标直接寻址;
- 尾部 add:均摊 O (1),仅扩容时拷贝;
- 头部 / 中间 add (int)/remove (int):O (n),数组整体移位复制。
1.2.5 fail-fast 快速失败机制
增删时 modCount 自增,迭代器创建保存expectedModCount,遍历对比两者不一致直接抛出ConcurrentModificationException,仅用于检测 bug,不能并发同步。
1.2.6 线程安全问题
无同步锁,多线程读写会数组越界、数据丢失;安全方案:List list = Collections.synchronizedList(new ArrayList<>())。