Java 面试:ArrayList 和 LinkedList 到底有什么区别?
摘要
ArrayList 和 LinkedList 是 Java 面试里非常高频的基础题。很多人只会背“ArrayList 查询快,LinkedList 增删快”,但这个说法其实不够严谨。本文用面试视角,简单梳理它们的底层结构、性能区别、使用场景和常见追问。
前言
上一篇文章梳理了 Java 集合体系,讲了 List、Set、Map 怎么分类。
这一篇继续讲 List 下面最常问的两个实现类:
ArrayListLinkedList
这个题不难,但面试时很多人容易答得太死:
ArrayList 查询快,LinkedList 增删快。
这句话不是完全错,但不够准确。
这篇就用比较短的方式,把这个问题讲清楚。
一、面试官一般怎么问?
常见问法有这些:
ArrayList和LinkedList有什么区别?- 它们底层数据结构是什么?
- 哪个查询快?哪个增删快?
- 为什么实际开发中
ArrayList用得更多? LinkedList真的适合频繁增删吗?ArrayList扩容机制了解吗?
二、先给结论
一句话先记住:
ArrayList底层是数组,随机访问快;LinkedList底层是双向链表,插入删除节点本身方便,但如果要先查找位置,也需要遍历。
更准确一点:
ArrayList:适合查询多、尾部追加多的场景LinkedList:适合已经定位到节点后,频繁插入删除的场景- 实际开发中,
ArrayList使用频率更高
不要简单死背:
ArrayList 查询快,LinkedList 增删快
这句话面试时最好补一句:
LinkedList 增删快的前提是已经定位到节点。如果还要按下标查找位置,它也需要遍历,不一定比 ArrayList 快。
三、ArrayList 是什么?
ArrayList 底层是数组。
它的特点是:
- 查询快
- 支持下标随机访问
- 尾部追加效率高
- 中间插入、删除可能需要移动元素
- 容量不够时会扩容
简单示例:
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Spring");
list.add("MySQL");
System.out.println(list.get(1));
输出:
Spring
因为底层是数组,所以可以通过下标快速访问。
比如:
list.get(1);
它可以直接根据下标定位元素。
四、ArrayList 的优缺点
优点
ArrayList 最大的优点是查询快。
因为数组支持随机访问,按下标取值非常方便。
String value = list.get(0);
这种操作效率很高。
另外,尾部追加元素也比较常见:
list.add("Redis");
只要没有触发扩容,尾部追加效率也不错。
缺点
ArrayList 的缺点主要是中间插入和删除可能比较慢。
比如在中间插入:
list.add(1, "Kafka");
数组后面的元素需要整体往后移动。
删除中间元素也是类似:
list.remove(1);
后面的元素需要往前移动。
所以如果频繁在中间插入、删除,ArrayList 的成本会变高。
五、LinkedList 是什么?
LinkedList 底层是双向链表。
每个节点除了存数据,还会保存前一个节点和后一个节点的引用。
可以简单理解成:
prev <- node -> next
它的特点是:
- 不支持快速随机访问
- 查找某个位置需要遍历
- 插入、删除节点本身比较方便
- 内存占用相对更高
简单示例:
List<String> list = new LinkedList<>();
list.add("Java");
list.add("Spring");
list.add("MySQL");
System.out.println(list.get(1));
这段代码也能正常运行。
但需要注意:
LinkedList 虽然也有 get(index) 方法,但它不是数组,不能直接通过下标定位。
它需要从头或从尾开始遍历。
六、LinkedList 的优缺点
优点
LinkedList 的优点是节点插入、删除本身比较方便。
如果已经定位到了某个节点,只需要调整前后节点指针。
不像数组那样需要整体移动一批元素。
缺点
LinkedList 的缺点也很明显。
第一,查询慢。
因为它不能像数组一样直接根据下标访问,需要遍历。
第二,内存占用更高。
因为每个节点不仅要存数据,还要存前后指针。
第三,实际开发中很多所谓“增删场景”,也需要先查找位置。
如果你要先按下标找到某个位置,再插入或删除,那么查找这一步就已经有成本了。
所以不要简单认为:
只要增删多,就一定用 LinkedList。
七、查询和增删到底怎么比较?
这个是面试重点。
1. 查询
ArrayList 查询快。
原因:
- 底层是数组
- 支持随机访问
- 可以通过下标直接定位
时间复杂度一般是:
O(1)
LinkedList 查询慢。
原因:
- 底层是链表
- 按下标查询需要遍历
时间复杂度一般是:
O(n)
2. 插入和删除
如果是在尾部追加:
list.add("Java");
ArrayList 通常也很快。
如果是在中间插入或删除,ArrayList 可能需要移动元素。
list.add(1, "Spring");
list.remove(1);
LinkedList 插入删除节点本身比较快,但前提是:
已经定位到要操作的节点。
如果还要先根据下标找节点,那也要遍历。
所以更准确的说法是:
ArrayList 随机访问快;
LinkedList 在已定位节点的情况下,插入删除比较方便。
八、为什么实际开发中 ArrayList 用得更多?
实际开发中,ArrayList 用得更多。
原因主要有几个:
1. 查询场景更多
很多业务代码里,集合更多是用来存一批数据,然后遍历、查询、转换。
这种场景 ArrayList 更合适。
2. 尾部追加很常见
比如:
List<UserVO> result = new ArrayList<>();
for (User user : userList) {
result.add(convert(user));
}
这种代码很常见。
大多数时候都是往集合尾部追加元素,ArrayList 完全够用。
3. LinkedList 内存开销更大
LinkedList 每个节点都要额外存前后引用。
数据量大时,内存占用会更高。
4. LinkedList 的优势没有想象中那么大
很多人以为 LinkedList 增删一定快。
但实际场景中,如果你不是已经拿到了节点,而是通过下标找位置,再插入删除,那么它也需要遍历。
所以优势没那么绝对。
九、ArrayList 扩容简单了解一下
ArrayList 底层是数组,数组长度固定。
当元素数量超过当前数组容量时,就需要扩容。
扩容大概过程是:
- 创建一个更大的新数组
- 把旧数组元素复制过去
- 新元素继续添加
所以如果能预估数据量,可以提前指定容量。
比如:
List<String> list = new ArrayList<>(1000);
这样可以减少扩容次数。
面试时可以简单说:
ArrayList 底层是数组,容量不够时会扩容。扩容会创建新数组并复制旧数据,所以如果能预估数据量,可以提前指定初始容量,减少扩容成本。
十、常见追问
1. ArrayList 是线程安全的吗?
不是。
ArrayList 不是线程安全的。
多线程同时修改同一个 ArrayList,可能出现数据不一致或并发问题。
如果需要线程安全,可以考虑:
Collections.synchronizedListCopyOnWriteArrayList- 自己加锁
2. LinkedList 是线程安全的吗?
也不是。
LinkedList 同样不是线程安全的。
多线程共享修改时,也需要额外保证线程安全。
3. ArrayList 和 Vector 有什么区别?
Vector 是线程安全的,很多方法加了 synchronized。
但因为同步开销比较大,现在实际开发中用得比较少。
常见回答:
ArrayList 不是线程安全的,性能相对更好;
Vector 是线程安全的,但很多方法加了 synchronized,性能开销更大,现在用得比较少。
4. LinkedList 能不能当队列用?
可以。
LinkedList 实现了 Deque 接口,可以当队列或双端队列使用。
比如:
Deque<String> deque = new LinkedList<>();
deque.offer("task1");
deque.offer("task2");
System.out.println(deque.poll());
但实际开发中,如果只是做队列,也可以考虑 ArrayDeque。
十一、面试回答模板
问:
ArrayList 和 LinkedList 有什么区别?
答:
ArrayList 底层是数组,支持根据下标随机访问,所以查询效率高,尾部追加元素也比较常见。但如果在中间插入或删除元素,可能需要移动后面的元素。
LinkedList 底层是双向链表,插入和删除节点本身比较方便,但它不支持快速随机访问,如果根据下标查询元素,需要从头或从尾遍历。
所以不能简单说 ArrayList 查询快、LinkedList 增删快。更准确地说,ArrayList 随机访问快;LinkedList 在已经定位到节点的情况下,插入删除比较方便。
实际开发中,ArrayList 用得更多,因为大多数场景都是查询、遍历、尾部追加,LinkedList 的优势没有想象中那么明显。
这段回答基本就够用了。
如果面试官继续追问,再展开:
ArrayList扩容- 线程安全问题
VectorCopyOnWriteArrayListLinkedList和ArrayDeque
十二、一句话总结
ArrayList 底层是数组,随机访问快,适合查询和尾部追加。
LinkedList 底层是双向链表,插入删除节点本身方便,但按下标查找需要遍历。
别死背:
ArrayList 查询快,LinkedList 增删快
更准确的说法是:
ArrayList 随机访问快;LinkedList 在已定位节点的情况下,插入删除方便。
实际开发中,大多数场景优先考虑 ArrayList。
大家加油:)
更多推荐

所有评论(0)