目录
核心概括
-
ArrayList:底层是动态数组。像一辆在轨道上运行的列车,车厢(元素)在内存中连续排列。
-
LinkedList:底层是双向链表。像一队手拉手的人,每个人(节点)都知道自己前后是谁,但他们在内存中的位置是分散的。
详细对比表格

深入原理分析
1. ArrayList:动态数组
-
工作原理:
-
内部维护一个
Object[] elementData数组。 -
当使用
get(int index)时,直接通过数组下标elementData[index]访问,所以速度极快。 -
当在列表中间或开头插入元素时(
add(int index, E element)),例如在位置i插入,需要将i之后的所有元素都向后移动一位,这是一个 O(n) 操作。 -
当数组容量不足时,会创建一个新的更大的数组(通常是原来的1.5倍),并将旧数组的数据拷贝过去,这个过程称为扩容,性能开销较大。
-
-
代码示例:体现插入的劣势
ArrayList<Integer> arrayList = new ArrayList<>();
// 先添加100000个元素
for (int i = 0; i < 100000; i++) {
arrayList.add(i);
}
long start = System.currentTimeMillis();
arrayList.add(0, -1); // 在开头插入一个元素,需要移动后面所有元素!
long end = System.currentTimeMillis();
System.out.println("ArrayList time: " + (end - start) + "ms");
2. LinkedList:双向链表
-
工作原理:
-
内部定义了一个
Node节点类,包含item(数据)、next(指向下一个节点)、prev(指向上一个节点)。 -
当需要访问第
index个元素时,get(int index)方法会判断index更靠近头部还是尾部,然后从头或尾开始遍历,直到找到目标位置。这是一个 O(n) 操作。 -
当在已知位置插入或删除元素时,例如在节点
A和B之间插入节点C,只需要修改引用:-
A.next = C -
C.prev = A -
C.next = B -
B.prev = C
这个操作是 O(1) 的。
-
-
-
代码示例:体现插入的优势
LinkedList<Integer> linkedList = new LinkedList<>();
// 先添加100000个元素
for (int i = 0; i < 100000; i++) {
linkedList.add(i);
}
long start = System.currentTimeMillis();
linkedList.add(0, -1); // 在开头插入,只需修改第一个节点的prev和新节点的next
long end = System.currentTimeMillis();
System.out.println("LinkedList time: " + (end - start) + "ms");
数据结构差异
LinkedList 基于双向链表实现,每个元素(节点)存储数据及前后节点的引用。
ArrayList 基于动态数组实现,元素在内存中连续存储,通过索引直接访问。
时间复杂度对比
插入/删除操作:
LinkedList 在头尾插入/删除时间复杂度为 O(1),中间位置为 O(n)(需遍历定位)。
ArrayList 尾部插入/删除为 O(1),中间或头部操作可能导致数组移动,平均为 O(n)。
随机访问:
LinkedList 需遍历节点,时间复杂度 O(n)。
ArrayList 通过索引直接访问,时间复杂度 O(1)。
内存占用与扩容
LinkedList 每个节点需额外存储前后指针,内存开销较大。
ArrayList 内存连续,但动态扩容时需拷贝数据到新数组(默认扩容 1.5 倍)。
适用场景
选择 ArrayList 的情况(绝大多数场景):
-
频繁按索引访问元素(
get和set操作)。 -
大部分操作是在列表的末尾进行添加和删除(
add(E element),remove(int index)且 index 很大)。 -
对内存空间敏感,希望占用更少的内存。
结论:由于在开发中查询的次数远大于增删,所以
ArrayList是更常用的选择。
选择 LinkedList 的情况:
-
需要频繁在列表的中间或开头进行插入和删除操作。
-
需要将列表当作栈、队列或双端队列来使用(因为它实现了
Deque接口)。 -
不确定列表的大小,且非常频繁地进行动态增删,无法接受
ArrayList扩容带来的性能损耗。
线程安全
两者均非线程安全,需通过 Collections.synchronizedList 或并发容器(如 CopyOnWriteArrayList)实现同步。

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



