1. ArrayList与LinkedList的本质区别
作为Java开发者,我们每天都在和集合框架打交道。ArrayList和LinkedList这对"孪生兄弟"虽然都实现了List接口,但骨子里却有着截然不同的基因。理解它们的底层实现差异,是写出高性能代码的基础。
1.1 底层数据结构对比
ArrayList的底层是一个动态数组。当我们创建ArrayList时,它会在内存中分配一块连续的空间。这个设计带来了几个关键特性:
- 内存连续:所有元素肩并肩地排在一起
- 自动扩容:当数组填满时,会创建一个更大的新数组(通常是原大小的1.5倍)
- 预留空间:为了避免频繁扩容,通常会预留一些空位
java复制// ArrayList扩容核心代码(简化版)
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5倍
elementData = Arrays.copyOf(elementData, newCapacity);
}
而LinkedList则是典型的双向链表结构。每个元素(Node)都保存着:
- 数据本身(item)
- 前驱节点引用(prev)
- 后继节点引用(next)
java复制// LinkedList节点定义
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
// 构造方法...
}
这种结构决定了LinkedList的内存是不连续的,每个元素都可以分散在内存的不同位置。
关键理解:数组的连续内存 vs 链表的指针跳转,这个根本差异导致了它们所有的性能区别。
1.2 内存布局可视化
让我们用图示来更直观地理解它们的内存布局:
ArrayList内存布局
code复制索引: 0 1 2 3 4
[A] -> [B] -> [C] -> [D] -> [E]
↑ ↑ ↑ ↑ ↑
连续内存地址(例如0x1000,0x1004,0x1008...)
LinkedList内存布局
code复制节点A @0x2000: [prev=null, item=A, next=0x3000]
节点B @0x3000: [prev=0x2000, item=B, next=0x4000]
节点C @0x4000: [prev=0x3000, item=C, next=null]
可以看到,LinkedList的节点在内存中是完全分散的,通过指针连接。而ArrayList则是整齐排列的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 关键操作性能对比
理解了底层结构,我们就能预测不同操作的性能表现了。这里我整理了一个详细的对比表格:
2.1 时间复杂度对比
| 操作 | ArrayList | LinkedList |
|--------------------
