1. ArrayList 概述
1.1 什么是 ArrayList
ArrayList
是 Java 集合框架中的一个类,它实现了动态数组的数据结构。与普通数组相比,ArrayList
具有动态调整大小的能力,使得我们可以轻松地进行元素的插入和删除。
1.2 关键特性
-
动态数组: 能够自动调整大小,根据需要动态分配内存。
-
快速随机访问: 可以通过索引迅速访问元素,具有常数时间的随机访问性能。
-
实现了 List 接口: 提供了与列表相关的所有操作。
2. ArrayList 的动态扩容机制
2.1 初始容量
ArrayList
在初始化时会分配一块初始容量的内存,这个容量通常为 10。初始容量的选择是一个折中,既要保证足够的空间,又要避免浪费内存。
2.2 添加元素时的扩容
当往 ArrayList
中添加元素时,会首先检查当前元素个数是否已经达到了容量。如果已经达到,就需要进行扩容。
2.2.1 新容量的计算
新容量一般是旧容量的 1.5 倍。这是通过以下代码计算的:
int newCapacity = oldCapacity + (oldCapacity >> 1);
2.2.2 数据迁移
然后,将旧数组中的元素复制到新数组中。这个过程涉及数组的复制和内存的分配,是相对耗时的操作。
// 模拟数组复制
Object[] newElementData = new Object[newCapacity];
System.arraycopy(elementData, 0, newElementData, 0, size);
elementData = newElementData;
2.3 扩容的优化
为了避免每次添加元素都触发扩容操作,可以在创建 ArrayList
时通过构造函数指定初始容量,使其足够大以容纳预期的元素数量。
ArrayList<String> list = new ArrayList<>(100); // 指定初始容量为 100
3. ArrayList 的性能考虑
3.1 扩容的代价
尽管 ArrayList
提供了动态扩容的机制,但频繁的扩容会带来性能问题。因此,在能预知元素数量的情况下,最好在创建时就指定一个合适的初始容量。
3.2 避免使用中间位置插入和删除
由于数组是一种顺序存储结构,如果在中间位置插入或删除元素,后续的元素都需要移动,这样的操作效率较低。
4. ArrayList 的最佳实践
4.1 提前规划容量
在创建 ArrayList
时,如果能够预知元素的数量,最好提前规划好初始容量,避免动态扩容的频繁发生。
4.2 批量操作
在批量操作时,如添加一组元素,可以使用 addAll
方法,它在一次扩容操作中添加了多个元素,相比于多次添加单个元素,效率更高。
List<String> newElements = Arrays.asList("A", "B", "C");
list.addAll(newElements) ;