不能把Deque当成普通List用,因为其设计目标是双端操作而非随机访问,get(int index)不保证O(1),如LinkedList的get()为O(n),ArrayList实现Deque时首尾操作性能极差。

为什么不能把 Deque 当成普通 List 用
因为 Deque 的设计目标不是随机访问,而是双端操作。它不保证 get(int index) 是 O(1) —— 比如 LinkedList 实现的 Deque,调用 get(5000) 会从头或尾遍历,实际是 O(n);而 ArrayList 虽然实现了 Deque 接口,但它的 addFirst() 和 removeLast() 都要移动大量元素,性能极差。
常见错误现象:
- 用 ArrayDeque 写 list.get(i) 做遍历,发现越往后越慢
- 把 LinkedList 当作“既能当队列又能当列表”的万能容器,结果在中间插入/查找时卡顿
-
Deque关键方法是offerFirst()、pollLast()、peek(),不是get()或set() - 若需要按索引查改 + 频繁首尾增删 → 选
ArrayList(首部操作少)或ArrayDeque(只做首尾,不索引访问) -
LinkedList在 Java 21+ 已被明确标记为“legacy”,官方建议用ArrayDeque替代其双端队列用途
ArrayDeque 和 ArrayList 在栈/队列场景下的真实开销差异
ArrayDeque 底层是循环数组,扩容时复制数组但只复制有效段;ArrayList 扩容是整块复制,且首部插入需整体位移。实测插入 10 万次到头部:
- ArrayList.add(0, x):约 8 秒(JDK 17)
- ArrayDeque.offerFirst(x):约 8 毫秒
Dequestack = new ArrayDeque<>(); stack.push("a"); // 等价于 offerFirst stack.pop(); // 等价于 pollFirst Deque
queue = new ArrayDeque<>(); queue.offer("b"); // 等价于 offerLast queue.poll(); // 等价于 pollFirst
-
ArrayDeque不允许null元素,ArrayList允许 —— 这是运行时才暴露的兼容性坑 -
ArrayDeque的初始容量是 16,但不会像ArrayList那样在add()时立即扩容;它更懒,直到真正填满才扩 - 如果业务需要“带索引的队列”(比如取第 3 个待处理任务),别硬套
Deque,老实用ArrayList+ 明确注释说明访问模式
什么时候该用 List,什么时候必须用 Deque
看操作模式,不是看“要不要存多个值”。List 的语义是“有序序列,支持位置定位”;Deque 的语义是“双端线性结构,支持 LIFO/FIFO 行为”。
- 需要
subList()、indexOf()、sort()、或频繁for (int i=0; i→ 必须 List - 实现撤销栈(
push/pop)、BFS 队列(offer/poll)、滑动窗口(offerLast+pollFirst当超长)→ 优先ArrayDeque - 需要线程安全的双端队列?不用
synchronized(new LinkedList()),直接用ConcurrentLinkedDeque—— 它不实现List,也不支持get()
Deque 实现类选型的隐藏约束
ArrayDeque 不是万能的:它不能序列化为 JSON 时保持顺序(某些库会把它当 Collection 扁平输出),也不能直接传给期待 List 的 Spring Data JPA 方法(比如 repository.findAllById(list) 会报 ClassCastException)。
- Spring Boot 3.x 默认 Jackson 会把
ArrayDeque序列化成数组,但反序列化时若字段声明为Deque,可能构造出LinkedList实例(取决于模块注册) - MyBatis 中
可能失败,因为 MyBatis 对Deque的反射支持弱于List - 如果你写的工具方法签名是
void process(List,就别传items) ArrayDeque进去 —— 即使它“恰好”实现了List(ArrayList和ArrayDeque都没实现List!只有LinkedList同时实现两者)
最常被忽略的一点:ArrayDeque 和 LinkedList 都实现了 Deque,但只有 LinkedList 实现了 List;而 ArrayList 实现了 List 却没实现 Deque —— 接口实现不是按“功能相似”自动继承的,得看源码里写了几个 implements。
立即学习“Java免费学习笔记(深入)”;










