从源码深挖 ArrayList 与 LinkedList 的性能差异
在 Java 集合框架中,ArrayList 和 LinkedList 作为 List 接口的两个典型实现,经常被拿来对比。很多开发者仅停留在'ArrayList 基于数组、LinkedList 基于链表'的表层认知,却忽略了底层源码设计对性能的决定性影响。本文将从源码出发,从初始化、增删改查、内存占用等多维度拆解两者的性能差异,帮你在实际开发中精准选型。
底层结构:数组 vs 双向链表
要理解性能差异,首先得从两者的底层数据结构说起,这是一切性能表现的根源。
ArrayList:动态扩容的 Object 数组
ArrayList 的核心是一个 transient Object[] elementData 数组,Java 源码中定义如下:
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer.
*/
transient Object[] elementData; // non-private to simplify nested class access
数组的特性是内存连续存储,这让随机访问可以通过下标直接定位,时间复杂度为 O(1);但也带来了扩容成本和插入删除时的元素移动开销。
LinkedList:带首尾指针的双向链表
LinkedList 的底层是双向链表结构,每个节点用 Node 类封装:
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
同时维护了首尾节点指针:
transient Node<E> first;
transient Node<E> last;
链表的节点在内存中分散存储,通过指针关联,插入删除仅需改变指针指向,但随机访问需要遍历链表,时间复杂度为 O(n)。
核心操作性能对比
接下来我们从源码角度,逐一分析增、删、改、查四大核心操作的性能差异。
查找:ArrayList 完胜,O(1) vs O(n)
ArrayList 的随机访问:直接通过数组下标定位,源码非常简洁:
public E get(int index) {
Objects.checkIndex(index, size);
return elementData(index);
}
E elementData( index) {
(E) elementData[index];
}


