LinkedList vs ArrayList:谁更快?到底该怎么选?
🚀 高频指数:★★★★★
🎯 你将收获:底层结构对比、时间复杂度分析、源码解读、项目选型模板。
一、面试开场问题
💬 面试官:
- ArrayList 和 LinkedList 有什么区别?
- 哪个增删快?哪个查询快?
- 为什么 LinkedList 在实际项目中用得少?
答得好,能体现你对集合原理、内存模型和性能评估的理解;
答得背板,就容易掉入“LinkedList 增删快”这种半真半假的陷阱。
二、核心区别概览
| 对比项 | ArrayList | LinkedList |
|---|---|---|
| 底层结构 | 动态数组 | 双向链表 |
| 随机访问 | ✅ O(1) 通过索引 | ❌ O(n) 需遍历 |
| 插入删除 | ❌ O(n)(需移动元素) | ✅ O(1)(已定位节点) |
| 内存开销 | 小(连续数组) | 大(节点额外引用) |
| 线程安全 | ❌ 不安全 | ❌ 不安全 |
| 实现接口 | List, RandomAccess | List, Deque |
| 是否支持队列操作 | 部分支持 | ✅ 完整支持(双端队列) |
📌 口诀:“查快数组,增快链表。”
三、底层结构源码对比
🔹 ArrayList(动态数组)
transient Object[] elementData;
private int size;
- 内部维护一个连续的 Object 数组;
- 通过索引直接访问元素。
🔹 LinkedList(双向链表)
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
}
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
- 每个节点存储前后指针,双向连接。
- 访问中间元素必须从头或尾遍历。
四、增删性能对比
| 操作 | ArrayList | LinkedList |
|---|---|---|
| add(E e)(尾部) | O(1)*均摊 | O(1) |
| add(int index, E e) | O(n)(移动元素) | O(n)(先遍历,再插入) |
| remove(int index) | O(n) | O(n) |
| removeFirst()/removeLast() | ❌ | ✅ O(1) |
| clear() | O(n) 逐个置空 | O(1)(断开首尾) |
✅ LinkedList 只在首尾增删优势明显,
中间插入时仍需遍历,性能优势有限。
五、访问性能对比
list.get(i);
- ArrayList:底层数组,直接通过下标定位 → O(1);
- LinkedList:必须从头或尾开始迭代 → O(n)。
📌 口诀:“数组随机,链表顺序。”
六、内存与缓存效率
| 指标 | ArrayList | LinkedList |
|---|---|---|
| 存储模型 | 连续内存块 | 分散节点 |
| 空间占用 | 少 | 多(每个节点额外两个引用) |
| CPU 缓存友好性 | ✅ 连续存储,局部性好 | ❌ 不连续,命中率低 |
| 适合场景 | 数据量大、访问频繁 | 插入删除频繁但数据量小 |
⚙️ 实际工程中:ArrayList 在绝大多数场景下更快。
七、源码关键差异举例
🔹 ArrayList.get()
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
直接数组访问 → O(1)。
🔹 LinkedList.get()
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
Node<E> node(int index) {
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
遍历一半链表,O(n) 时间复杂度。
八、fail-fast 同样存在
两者都继承自 AbstractList,共享 modCount 机制。
在遍历时若结构被修改,都会抛出 ConcurrentModificationException。
九、项目实践选型建议
| 场景 | 推荐集合 | 理由 |
|---|---|---|
| 随机访问频繁(查询多) | ✅ ArrayList | O(1) 访问快 |
| 插入删除首尾元素 | ✅ LinkedList | 双端队列 O(1) 操作 |
| 中间插入删除多 | ArrayList | 因 LinkedList 仍需遍历 |
| 数据量大(10w+) | ✅ ArrayList | 内存与缓存效率更高 |
| 队列/栈场景 | ✅ LinkedList / ArrayDeque | 实现 Deque 接口更自然 |
💡 实际项目中 95% 场景优先 ArrayList。
LinkedList 更适合模拟队列、缓存、链式结构。
十、性能对比实测(样例)
List<Integer> arr = new ArrayList<>();
List<Integer> link = new LinkedList<>();
int N = 50000;
long t1 = System.nanoTime();
for (int i = 0; i < N; i++) arr.add(i);
System.out.println("ArrayList add: " + (System.nanoTime() - t1));
t1 = System.nanoTime();
for (int i = 0; i < N; i++) link.add(i);
System.out.println("LinkedList add: " + (System.nanoTime() - t1));
t1 = System.nanoTime();
arr.get(N/2);
System.out.println("ArrayList get: " + (System.nanoTime() - t1));
t1 = System.nanoTime();
link.get(N/2);
System.out.println("LinkedList get: " + (System.nanoTime() - t1));
输出结果(示例):
ArrayList add: 2.3 ms
LinkedList add: 4.8 ms
ArrayList get: 0.01 µs
LinkedList get: 380 µs
✅ 访问性能差距显著,ArrayList 完胜。
十一、面试官追问清单
| 问题 | 答案要点 |
|---|---|
| ArrayList 与 LinkedList 区别? | 底层结构不同,数组 vs 链表。 |
| 哪个增删快? | 首尾 LinkedList 快,中间基本一样。 |
| 哪个查找快? | ArrayList O(1);LinkedList O(n)。 |
| 为什么 LinkedList 慢? | 遍历需移动节点指针,CPU 缓存不友好。 |
| 项目中选哪个? | 绝大多数选 ArrayList。 |
十二、口诀记忆
☕️ “查快数组,增快链表;首尾高效,中间无差。”
十三、小结
| 知识点 | 关键结论 |
|---|---|
| 底层结构 | ArrayList=数组,LinkedList=链表 |
| 查询性能 | ArrayList 快 |
| 插入删除 | 仅首尾 LinkedList 快 |
| 空间效率 | ArrayList 优 |
| 实战选型 | 默认 ArrayList,链式结构才选 LinkedList |
✅ 一句话总结:“能用 ArrayList,就别用 LinkedList。”

被折叠的 条评论
为什么被折叠?



