一、底层数据结构
// JDK 1.8 ArrayList部分源码
transient Object[] elementData; // 存储元素的数组缓冲区
private int size; // 当前元素数量二、构造方法解析
// 无参构造(使用默认容量)
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// 指定初始容量构造
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException(...);
}
}
// 集合参数构造
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}三、关键成员变量
| 变量名 | 作用 |
|---|---|
| DEFAULT_CAPACITY | 默认初始容量10 |
| MAX_ARRAY_SIZE | 最大数组长度Integer.MAX_VALUE - 8 |
| modCount | 结构性修改计数器(用于快速失败机制,迭代时检测并发修改) |
三、add方法执行流程
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 容量检查
elementData[size++] = e; // 添加元素
return true;
}四、remove方法执行流程
public E remove(int index) {
rangeCheck(index); // 索引范围检查
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index, numMoved);
elementData[--size] = null; // 清除引用,帮助GC
return oldValue;
}执行流程:
- 检查索引是否越界(rangeCheck)
- 修改计数器递增(modCount++)
- 获取被删除元素
- 计算需要移动的元素数量
- 使用System.arraycopy移动后续元素
- 将最后一个位置置空并调整size
- 返回被删除元素
五、扩容机制核心代码
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);
}五、扩容示例验证
// 测试代码
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
list.add(i);
System.out.println("第"+(i+1)+"次添加,当前容量:"
+ getCapacity(list));
}
// 反射获取真实容量
static int getCapacity(ArrayList<?> list) throws Exception {
Field field = ArrayList.class.getDeclaredField("elementData");
field.setAccessible(true);
return ((Object[]) field.get(list)).length;
}七、迭代器实现原理
private class Itr implements Iterator<E> {
int cursor; // 下一个元素索引
int lastRet = -1; // 最后访问元素索引
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
public E next() {
checkForComodification();
// ... 实际获取元素逻辑
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}八、性能对比数据
| 初始容量 | 添加10万元素耗时(ms) |
|---|---|
| 默认10 | 35 |
| 指定100000 | 8 |
六、扩容规律总结
| 元素数量 | 实际容量 |
|---|---|
| 10 | 10 |
| 11 | 15 |
| 16 | 22 |
| 23 | 33 |
| 34 | 49 |
通过源码分析可见,ArrayList采用1.5倍系数扩容,在空间和时间效率之间取得平衡。开发中应根据业务场景合理设置初始容量,避免频繁扩容带来的性能损耗。
参考资料
- Oracle Java Collections Framework官方文档
- 《Effective Java(第三版)》 第4章 类和接口
- 《Java核心技术 卷Ⅰ》 第9章 集合
- Google Guava Collections指南
本文详细介绍了 ArrayList核心源码解析与扩容机制详解,希望对您有所帮助。如果您有任何问题,欢迎在评论区讨论!

