JDK 8 ArrayList 详解及详细源码展示
JDK 8 的 ArrayList
是 Java 集合框架中的核心实现,基于 动态数组 实现,支持快速随机访问和动态扩容。本文结合源码剖析其设计哲学、核心实现及性能优化技术。
一、核心设计目标:动态数组与快速随机访问
1.1 动态数组特性
- 自动扩容:当元素数量超过当前容量时,自动扩容为原来的 1.5 倍。
- 容量缩减:通过
trimToSize()
方法可手动缩减容量。
1.2 快速随机访问
- 索引直接映射:通过
get(int index)
方法,时间复杂度为 O(1)。 - 内存连续性:底层基于数组实现,元素在内存中连续存储。
二、源码核心类结构
// java.util.ArrayList.java
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
// 默认初始容量
private static final int DEFAULT_CAPACITY = 10;
// 空数组(用于延迟初始化)
private static final Object[] EMPTY_ELEMENTDATA = {};
// 默认空数组(当用户使用无参构造时使用)
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 底层数组
transient Object[] elementData;
// 元素数量
private int size;
// 修改次数(用于快速失败机制)
protected transient int modCount = 0;
// 构造方法
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("Illegal Capacity: "+ initialCapacity);
}
}
}
三、核心方法源码解析
3.1 add
方法
public boolean add(E e) {
// 确保容量足够
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 容量不足时扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// 扩容为原来的 1.5 倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 复制数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
3.2 get
方法
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
3.3 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;
}
四、关键优化技术
4.1 动态扩容策略
- 扩容因子:默认扩容为原来的 1.5 倍(
newCapacity = oldCapacity + (oldCapacity >> 1)
)。 - 容量限制:最大容量为
Integer.MAX_VALUE - 8
(避免内存溢出)。
4.2 内存局部性优化
- 连续内存:元素在内存中连续存储,提升缓存命中率。
- 数组复制:通过
System.arraycopy
优化数组复制性能。
4.3 快速失败机制
- 修改计数器:通过
modCount
字段检测并发修改。 - 迭代器检查:在迭代过程中,若
modCount
变化,抛出ConcurrentModificationException
。
五、典型应用场景
5.1 基础操作
// 创建 ArrayList
List<String> list = new ArrayList<>();
// 添加元素
list.add("A");
list.add("B");
// 随机访问
String element = list.get(1); // "B"
// 删除元素
list.remove(0);
5.2 批量操作
// 批量添加
List<String> subList = Arrays.asList("C", "D");
list.addAll(subList);
// 批量删除
list.removeAll(subList);
// 范围删除
list.subList(0, 2).clear();
5.3 性能优化
// 预分配容量(避免频繁扩容)
List<String> list = new ArrayList<>(1000);
// 手动缩减容量
list.trimToSize();
六、总结
JDK 8 的 ArrayList
通过动态数组、快速随机访问、自动扩容等核心技术,实现了高效的顺序存储。其源码实现深刻体现了数据结构与算法的精髓:
- 动态扩容:平衡时间和空间复杂度,减少频繁内存分配开销。
- 内存局部性:连续内存布局提升缓存命中率。
- 快速失败:通过
modCount
检测并发修改,保障迭代安全。
实际开发中,建议优先使用 ArrayList
,但在多线程场景下需改用 CopyOnWriteArrayList
或通过 Collections.synchronizedList
包装。深入理解其源码,有助于设计高性能的 Java 应用程序。