ArrayList 和 LinkedList 的区别?一篇讲透,从此开发和面试都不再纠结

在日常Java开发中,我们几乎每天都在使用List 。

而Java中最常用的两个列表实现就是 ArrayListLinkedList。面试官也是,非常喜欢问它们有什么区别。

很多朋友会死记硬背:"ArrayList 查询快,增删慢; LinkedList 查询慢,增删快。"

但你知道为什么吗?今天我们来深入的了解一下。


一、举个例子

你有一排书架:

ArrayList 就像一整排连续的书柜

所有书按顺序紧挨着放,编号 0、1、2......你想拿第5本书时,直接走过去拿就行,非常快!

LinkedList 就像用绳子串连起来的一堆独立小盒子

每个盒子里除了书,还写着前一个盒子在哪和后一个盒子在哪。你想拿第5本书时,得从第一个盒子开始,一个一个顺着绳子找过去。

下面我们再从技术角度进行深入分析。


二、底层结构:数组 vs 链表

ArrayList

ArrayList 底层是动态数组,元素在内存中是连续存放的。

java 复制代码
// ArrayList简化版原理
public class ArrayList {
    private Object[] elementData; // 核心数组
    private int size; // 当前元素个数
    
    // 添加元素时,如果数组满了会自动扩容
    public void add(Object element) {
        if (size == elementData.length) {
            // 创建一个1.5倍大的新数组,然后拷贝数据
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
        elementData[size++] = element;
    }
}

特点:

  • 内存中连续存储,像一排整齐的座位
  • 自动扩容,但扩容时需要拷贝所有数据
  • 访问速度快,但插入删除可能较慢

LinkedList

LinkedList 的底层是双向链表,元素在内存中是分散存放的,每个元素(节点)都记录着它前后邻居的"地址"。

java 复制代码
// LinkedList节点结构
class Node {
    E item;        // 当前节点数据
    Node next;     // 指向下一个节点
    Node prev;     // 指向上一个节点
}

// LinkedList简化版原理
public class LinkedList {
    private Node first; // 头节点
    private Node last;  // 尾节点
    private int size;
}

每个元素(节点)都保存着前后邻居的信息,就像每个人都知道自己前后是谁。


三、性能对比

我们从三个最常用的操作来看:

1. 随机访问(比如 list.get(100))

ArrayList:O(1)

直接跳到第 100 个位置,秒取!

LinkedList:O(n)

得从头开始数 100 次才能拿到。

结论 :如果你经常通过下标取数据(比如 for 循环遍历),ArrayList要快得多!


2. 在末尾添加/删除(list.add(obj) 或 remove(last))

ArrayList:平均 O(1)

正常情况直接加在最后;但如果空间满了,要扩容(复制整个数组),这时会慢一下(但平均下来还是很快)。

LinkedList:O(1)

直接在尾巴上挂新节点,永远不慢。

结论 :两者在尾部操作都很快,但 ArrayList 还是占优势(因为内存连续,CPU缓存友好)。


3. 在中间或开头插入/删除(比如 list.add(0, obj))

ArrayList:O(n)

插入第 0 位?后面所有元素都要往后挪一位!删也一样,前面空了,后面的要往前挤。

LinkedList:理论上 O(1),但实际常是 O(n)

虽然插入本身只要改指针,但你要先找到第 0 个节点啊!找的过程就要从头遍历,所以整体还是 O(n)。

重要提醒: 很多人以为 LinkedList 在中间插入更快,其实只有当你已经有那个位置的引用时才快(比如用 Iterator 遍历时删除)。

如果只是用 list.add(500, obj),它照样要先找第 500 个节点,速度并不比 ArrayList 快!


四、内存占用

ArrayList

只存数据和一点预留空间(比如容量 10,只用了 6,那有 4 个空位)。

LinkedList

每个元素都要额外存两个指针(指向前一个和后一个节点),内存开销大很多

举个例子:存1000个 Integer 对象:

  • ArrayList:约4KB(假设每个 int 4 字节)
  • LinkedList:约4KB(数据)+ 8KB(指针,每个指针 8 字节 × 2 × 1000)= 12KB+

结论ArrayList 更省内存,尤其存大量小对象时优势更加明显。


五、其他细节补充

是否支持"快速随机访问"?

  • ArrayList 实现了 RandomAccess 接口(这是一个标记接口,告诉程序员:"我支持快速随机访问")。
  • LinkedList 没有实现它。

有些工具类(如 Collections.binarySearch)会根据这个接口选择不同算法,进一步优化性能。

线程安全吗?

都不安全! 多线程环境下直接用会出问题。

如果需要线程安全,可以用:

java 复制代码
List<String> safeList = Collections.synchronizedList(new ArrayList<>());

或者用 CopyOnWriteArrayList(适合读多写少的场景)。

LinkedList 还能当队列用!

LinkedList 实现了 Deque 接口,可以当双端队列用:

java 复制代码
LinkedList<String> queue = new LinkedList<>();
queue.addFirst("A");
queue.addLast("B");
String first = queue.removeFirst(); // A

这时候它的链表结构就非常合适!


六、开发时该用哪个?

使用场景 推荐选择 原因
经常通过下标访问(如 for 循环、get(i)) ArrayList 随机访问快
主要在末尾增删(如日志记录、追加数据) ArrayList 简单高效,缓存友好
需要频繁在已知位置插入/删除(如用 Iterator 遍历时删元素) LinkedList 指针操作快
要实现队列、栈、双端队列 LinkedList 原生支持 addFirst/removeLast
内存紧张 or 存大量小对象 ArrayList 内存更紧凑

一般情况下,默认选 ArrayList 就对了!

只有在明确需要链表特性(如双端操作)时,才考虑 LinkedList。


总结

ArrayList 底层是数组,内存连续,访问快(O(1)),中间增删慢(O(n))。

LinkedList 底层是链表,内存分散,访问慢(O(n)),头尾增删快(O(1))。

日常开发中,优先选 ArrayList 准没错!

只有当你真的需要频繁在列表头尾增删、或者用它当队列/栈时,再考虑 LinkedList

本文首发于公众号:程序员刘大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!

📌往期精彩

《代码里全是 new 对象,真的很 Low 吗?我认真想了一晚》

《Java 开发必看:什么时候用 for,什么时候用 Stream?》

《这 5 个冷门 HTML 标签,让我直接删了100 行 JS 代码》

《Vue 组件通信的 8 种最佳实践,你知道几种?》

相关推荐
2601_962055975 小时前
跟据spring boot版本,查看对应的tomcat,并查看可支持的tomcat的版本范围
spring boot·后端·tomcat
EXI-小洲5 小时前
Java 操作 Word:字符串替换、图片插入、动态生成表格与API接口下载
java·开发语言·spring boot·word
2601_961901706 小时前
SpringBoot使用Nacos进行application.yml配置管理
java·spring boot·spring
Lost of 程序猿6 小时前
ASP.NET Core API 幂等性设计深度实战:从一次重复申领事故说起
后端·asp.net
何以解忧,唯有..6 小时前
LangChain 工具调用(Tool Calling)实战指南
java·前端·langchain
QQ_21696290967 小时前
【源码编号:project79475】SpringBoot校内二手交易平台:商品发布、分类检索、留言交流、订单管理全流程实战
java·spring boot·后端
前端 贾公子8 小时前
第09章:上下文与记忆 (2)
java·服务器·前端
2601_962203518 小时前
Java进阶07集合(续)
java·开发语言
郑州光合科技余经理8 小时前
本地生活服务系统:模块边界与结算字段怎么拆
java·开发语言·前端·后端·系统架构·uni-app·php
IT_陈寒8 小时前
Vue的嵌套组件竟然吃掉了我的事件?
前端·人工智能·后端