本篇文章是【Java集合系列】文章队列篇的第一篇,本系列将会逐个分析 Java 中的常用集合的特性及实现,然后对比不同场景下应该选择哪种集合使用。
List 系列
Queue系列
- ArrayDeque
- ConcurrentLinkedDeque
- LinkedBlockingDeque
ArrayDeque
ArrayDeque 是 Java 集合中双端队列的数组实现,双端队列的链表实现(LinkedList)我们在前几篇文章中讲过了。
ArrayDeque 几乎没有容量限制,设计为线程不安全的,禁止 null 元素。
ArrayDeque 作为栈使用时比 Stack 类效率要高,作为队列使用时比 LinkedList 要快。
ArrayDeque 大多数的额操作都在固定时间内运行,例外情况包括 remove
,removeFirstOccurrence
,removeLastOccurrence
,contains
,iterator.remove()
,和批量操作,这些将以线性时间运行。
iterator
同样也被设计为 fail-fast。
方法
ArrayDeque 作为 队列(FIFO) 使用时的方法:
队列方法 | 等效的双端队列方法 |
---|---|
add(e) | addLast(e) |
offer(e) | offerLast(e) |
remove() | removeFirst() |
poll() | pollFirst() |
element() | getFirst() |
peek() | peekFirst() |
ArrayDeque 作为 堆栈(FILO) 使用时的方法:
堆栈方法 | 等效的双端队列方法 |
---|---|
push(e) | addFirst(e) |
pop(e) | removeFirst(e) |
peek() | peekFirst() |
源码
我们先看看代码中最重要的三个变量:
transient Object[] elements;
transient int head;
transient int tail;
我们上面也说了 ArrayDeque 是双端队列的数组实现,上面代码可看到确实定义了一个用于存储链表数据数组:elements
,此外还定义了head
及tail
用于描述链表在数组中的头尾位置。另外说明一下,elements
长度始终未 2 的次方。
这里需要注意一点,用elements
存储的是双端队列,head
和tail
参数表示双端队列的头和尾的索引,但并不意味着head
值永远小于tail
,当tail
移动至数组末尾,但队列长度小于数组时(意味着此时head
大于0),再向队列末尾添加数据将会使tail
移动至数组的开头。
假设下图为当前的elements
数组,黄色方块表示其中有数据。
当我们向队列末尾添加一个元素时,数组变成了下面这样: