• 因为 Array 是基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的。Array 获取数据的时间复杂度是 O(1),但是要删除数据却是开销很大的,因为这需要重排数组中的所有数据。
  • 相对于 ArrayList,LinkedList 插入是更快的。因为 LinkedList 不像 ArrayList 一样,不需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重新装入一个新的数组,这是 ArrayList 最坏的一种情况,时间复杂度是 O(n),而 LinkedList 中插入或删除的时间复杂度仅为 O(1)。ArrayList 在插入数据时还需要更新索引(除了插入数组的尾部)。
  • 类似于插入数据,删除数据时,LinkedList 也优于 ArrayList。
  • LinkedList 需要更多的内存,因为 ArrayList 的每个索引的位置是实际的数据,而 LinkedList 中的每个节点中存储的是实际的数据和前后节点的位置。
  • 你的应用不会随机访问数据。因为如果你需要 LinkedList 中的第 n 个元素的时候,你需要从第一个元素顺序数到第 n 个数据,然后读取数据。
  • 你的应用更多的插入和删除元素,更少的读取数据。因为插入和删除元素不涉及重排数据,所以它要比 ArrayList 要快。

以上是教科书结论,但其中”LinkedList 插入删除 O(1)”这句话在真实使用中最容易被误用——它有一个隐藏前提。本文把复杂度前提、内存布局、缓存友好性三层补全,给出可直接执行的选型规则。

复杂度表(带前提)

操作 ArrayList LinkedList
get(i) 随机访问 O(1) O(n)
尾部 add 摊销 O(1) O(1)
头部/中部 add O(n)(搬运) O(1),前提是已持有该位置的迭代器/节点引用
按值查找后删除 O(n) O(n) 查找 + O(1) 删除
迭代器遍历中删除 O(n) 搬运 O(1)

关键澄清:list.add(0, x)、list.remove(i) 这类按索引操作,LinkedList 要先 O(n) 走到第 i 个节点,总体仍是 O(n),并不比 ArrayList 快多少;只有”迭代过程中就地增删”(迭代器已停在节点上)才是 LinkedList 真正的 O(1) 场景。面试与设计中把”LinkedList 增删快”无条件化,是最常见的误用来源。

内存与缓存:被忽略的决定性因素

  • ArrayList 是一块连续内存:对象引用紧凑排列,CPU 缓存行一次加载多个引用,遍历命中率极高
  • LinkedList 每个节点独立分配:节点对象头 + 数据引用 + prev/next 两个引用,内存开销约为 ArrayList 的 3-4 倍,且节点散落堆中,遍历时缓存缺失频繁

实测中即使”中部插入”场景,ArrayList 的 O(n) 内存搬运(memcpy 级速度)也常常跑赢 LinkedList 的 O(n) 寻址 + 指针操作 + 缓存缺失。算法复杂度相同量级时,内存布局决定常数项,这是教科书表格不写的部分。

扩容行为

ArrayList 默认初始容量 10,扩容为 1.5 倍并数组拷贝;已知大小时 new ArrayList<>(expectedSize) 可避免多次扩容。LinkedList 无扩容概念,但每个元素都有节点分配成本(高并发下还加剧 GC 压力)。

选型规则(可直接执行)

  • 默认 ArrayList:随机访问、遍历、尾部追加占绝大多数业务场景
  • 频繁头部插入删除且规模大 → 优先考虑 ArrayDeque(循环数组,两头 O(1),缓存友好),而不是 LinkedList
  • 迭代过程中大量就地增删 → LinkedList 或改用”标记-压缩”写法遍历 ArrayList
  • 需要队列语义 → ArrayDeque/LinkedBlockingQueue;需要双向遍历 → ListIterator(两者都支持,但 ArrayList 遍历更快)
  • 内存敏感的大集合 → ArrayList(节点开销差异在百万级元素时是 GB 级差距)

一个反直觉的基准结论

JMH 基准中常见结果:顺序遍历、按索引读、甚至中等规模的中部插入,ArrayList 全面领先;LinkedList 仅在”超大列表 + 迭代器就地增删”或”持续头部插入”时胜出。所以现代 Java 实践中 LinkedList 的出现频率越来越低——它不是错误答案,而是适用面比印象中窄得多的特化结构。

结论不变但更精确:ArrayList 赢在连续内存与随机访问,LinkedList 赢在持节点引用时的就地增删;选型时先问”我的增删是否持有迭代器位置”,再问”规模与内存是否敏感”,答案自然清晰。