网站首页 > 基础教程 正文
在 Java 集合框架中,ArrayList 是使用最广泛的集合之一。它是基于数组实现的动态数组,具有自动扩容的功能。扩容机制是 ArrayList 的一个重要特性,它让 ArrayList 能够应对动态变化的元素数量。接下来,我们将详细解读 ArrayList 的扩容机制,并结合源码进行说明。
源码解析
我们从 ArrayList 的构造函数和 add 方法入手,逐步揭示其扩容机制。
构造函数
ArrayList 有多个构造函数,其中最常用的是无参构造函数和带初始容量的构造函数。
java
// 无参构造函数
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);
}
}
无参构造函数会将 elementData 初始化为一个默认空数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA。而带初始容量的构造函数则根据提供的容量大小初始化数组。
add 方法
当我们向 ArrayList 中添加元素时,add 方法会检查是否需要扩容:
java
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 核心方法,确保容量
elementData[size++] = e;
return true;
}
ensureCapacityInternal 方法是扩容机制的核心:
java
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
当 minCapacity 超过当前数组长度时,会调用 grow 方法进行扩容。
grow 方法
grow 方法是扩容的关键部分:
java
private static final int DEFAULT_CAPACITY = 10;
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);
}
扩容的策略是将容量增加到原来的 1.5 倍 (oldCapacity + (oldCapacity >> 1)),同时确保新容量不小于 minCapacity。如果新容量超过了最大数组大小 MAX_ARRAY_SIZE,则调用 hugeCapacity 方法进行特殊处理。
扩容机制设计的目的
扩容机制的设计目的是为了在动态添加元素时,避免频繁的内存分配和数据复制。通过按需扩容,ArrayList 能够高效地管理内存,同时保持灵活性。
性能对比
我们可以通过以下代码示例来对比扩容机制的性能:
java
import java.util.ArrayList;
public class ArrayListPerfTest {
public static void main(String[] args) {
// 预先指定容量的 ArrayList
long startTime = System.nanoTime();
ArrayList<Integer> listWithCapacity = new ArrayList<>(1000000);
for (int i = 0; i < 1000000; i++) {
listWithCapacity.add(i);
}
long endTime = System.nanoTime();
System.out.println("ArrayList with initial capacity: " + (endTime - startTime) + " ns");
// 默认构造函数的 ArrayList
startTime = System.nanoTime();
ArrayList<Integer> listWithoutCapacity = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
listWithoutCapacity.add(i);
}
endTime = System.nanoTime();
System.out.println("ArrayList without initial capacity: " + (endTime - startTime) + " ns");
}
}
运行上述代码可以发现,预先指定容量的 ArrayList 性能更好,因为它避免了多次扩容操作。
实际应用场景
- 动态数据集合:在需要频繁添加元素的场景中,ArrayList 的扩容机制可以保证集合的动态性和灵活性。
- 大数据处理:在处理大数据集时,预先指定容量可以提高性能,减少扩容带来的开销。
?
猜你喜欢
- 2024-10-12 Java中Array,List,Set,ArrayList,Linkedlist集合的区别
- 2024-10-12 Array与ArrayList的区别 arraylist和arrays
- 2024-10-12 面试官和我聊一聊 ArrayList 面试redis
- 2024-10-12 ArrayList 和 LinkedList 源码分析
- 2024-10-12 Java集合框架,我花60分钟总结,你花20分钟记忆
- 2024-10-12 ArrayList 源码浅析 arraylist源码分析
- 2024-10-12 学点算法(一)——ArrayList内部数组实现元素去重
- 2024-10-12 面试官让我聊聊 ArrayList 解决了数组的哪些问题
- 2024-10-12 秋招啦!朋友,你不会现在连泛型都不清楚吧!不会吧不会吧
- 2024-10-12 每天一道面试题之Arraylist 与 LinkedList 区别
- 最近发表
- 标签列表
-
- gitpush (61)
- pythonif (68)
- location.href (57)
- tail-f (57)
- pythonifelse (59)
- deletesql (62)
- c++模板 (62)
- css3动画 (57)
- c#event (59)
- linuxgzip (68)
- 字符串连接 (73)
- nginx配置文件详解 (61)
- html标签 (69)
- c++初始化列表 (64)
- exec命令 (59)
- canvasfilltext (58)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- node教程 (59)
- console.table (62)
- c++time_t (58)
- phpcookie (58)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)