随机访问多就选 ArrayList:若代码频繁调用 get(i)、set(i, e) 或使用 for 循环遍历,则 ArrayList 性能更优,因其基于数组实现,支持 O(1) 时间复杂度的随机访问。

随机访问多就选 ArrayList
如果代码里频繁用 get(i)、set(i, e),或者遍历常用 for 循环(for (int i = 0; i ),ArrayList 是更优解。它底层是数组,get 是 O(1) 时间;而 LinkedList 每次 get(i) 都得从头或尾开始跳节点,平均 O(n/2),实际慢好几倍。
常见误用场景:
- 把 LinkedList 当作“更快的 List”来接收 JSON 解析结果或分页数据
- 在 for 循环中反复调用 list.get(i) 却没意识到开销
-
ArrayList的扩容机制(默认 1.5 倍)在写入量可预估时可通过构造函数指定初始容量,减少复制 -
LinkedList的get在 JDK 8+ 做了双向查找优化(比较i和size/2决定从头还是尾走),但仍是 O(n),无法改变本质
头部/尾部高频增删才考虑 LinkedList
LinkedList 真正有优势的只有:在列表开头频繁调用 addFirst(e)、removeFirst(),或在结尾频繁调用 addLast(e)、removeLast() —— 这些操作都是 O(1)。但它不等于“所有增删都快”。
典型踩坑:
- 用 list.add(0, e) 插入到 ArrayList 开头 → 触发整块数组后移,O(n)
- 以为 list.add(index, e) 在 LinkedList 中也快 → 实际要先 get(index) 定位,再插入,整体 O(n)
-
LinkedList的每个元素额外占用两个引用(prev/next),内存开销比ArrayList高约 2–3 倍 - 现代 CPU 缓存对数组友好,
ArrayList的连续内存让遍历速度远超LinkedList的分散节点
别拿 LinkedList 当队列/栈用
如果目标是队列语义(FIFO)或栈(LIFO),直接用专门类更安全高效:
- 队列 → ArrayDeque(非线程安全,无扩容锁,比 LinkedList 快且省内存)
- 线程安全队列 → ConcurrentLinkedQueue 或 BlockingQueue 实现类
- 栈 → ArrayDeque 的 push()/pop()(JDK 6+ 推荐,Stack 类已过时)
LinkedList 实现了 Deque 接口,但它的双链表结构在作为队列使用时,仍比 ArrayDeque 多指针操作和 GC 压力。
-
ArrayDeque扩容是 2 倍增长,没有ArrayList的 1.5 倍取整逻辑,但更利于位运算优化 -
LinkedList的迭代器虽支持快速失败(fail-fast),但并发修改检测不如CopyOnWriteArrayList明确,也不适合读多写少场景
实际选型看 profile,不是看名字
名字带 “List” 不代表适用所有 List 场景;名字带 “Linked” 更不等于“性能更好”。真实瓶颈往往不在理论复杂度,而在缓存局部性、GC 频率、JIT 优化程度。
立即学习“Java免费学习笔记(深入)”;
建议步骤:
- 先用 ArrayList,它是 90% 场景的合理默认值
- 如果压测发现 add(0, e) 或 remove(0) 成为热点,再尝试 ArrayDeque 或评估是否改用索引偏移等算法规避
- 只有确认是「双向、非随机、极高频头尾操作 + 内存不敏感」时,才保留 LinkedList
- JDK 17 的 JFR(Java Flight Recorder)能直接抓出
LinkedList.get的调用栈和耗时占比 - 用
ArrayList时注意避免list.get(list.size())这类越界错误,它抛IndexOutOfBoundsException;LinkedList同样抛这个异常,但堆栈更深,排查稍慢










