源码阅读(10):Java中主要的Queue、Deque结构——ArrayDeque集合(上)

本文深入剖析Java中的ArrayDeque集合,解释其作为双端队列(Deque)和栈结构的优势,以及核心的结构、初始化和添加操作。ArrayDeque基于循环数组实现,提供高效性能,其初始化容量最小为8,根据需要自动扩展为2的幂值。文章详细分析了addFirst(e)和addLast(e)方法中的关键运算式,确保元素在有效范围内循环使用。
摘要由CSDN通过智能技术生成

(接上文《源码阅读(9):Java中主要的Queue、Deque结构——概述》)

2.Java.util.ArrayDeque结构解析

ArrayDeque集合是从JDK 1.6版本开始推出的,这是一个基于数组(可扩容的数组)结构实现的双端队列。这个数组结构和普通的数组结构相比而言,前者是一个可循环使用的数组结构,这样的数组结构可以有效减少数组扩容的次数。ArrayDeque集合是线程不安全的,官方并不推荐在多线程环境下使用。

ArrayDeque集合既有队列、双端队列的操作特点,也有栈结构的操作特点。因此它是JDK 1.6 + 版本发布后,Java官方推荐的继Stack集合和LinkedList集合后,用来做“栈”结构操作的新的集合。在官方文档中也介绍了推荐原因:

"This class is likely to be faster than Stack when used as a stack, and faster than LinkedList when used as a queue. "

后一篇文章将详细分析为什么将ArrayDeque集合作为“栈”结构使用时,它的性能比Stack集合好,又为什么将它作为“队列”/“双端队列”结构使用时,它的性能又比LinkedList集合好。

2.1、ArrayDeque中的主要结构和方法

所谓可循环使用的数组结构是指这样的数组:其中定义了一个动态的有效范围,只有在这个有效范围内的元素才能被读写,并且这个有效范围不受数组本身结构的头部和尾部限制。如下图所示:

以上情况在ArrayDeque集合中都成立
实际上上图也就是ArrayDeque集合的主要结构了,可以看到ArrayDeque集合保持了一个数组,该数组变量名为“elements”;另外集合中保持了一个名为“head”的变量,用来标识下一次将被做“移除”操作的元素索引位(实际上就是“队列”/“双端队列”的头部索引位);最后,集合还保持了一个名为“tail”的变量,用来标识下一次将被做“添加”操作的元素索引位(实际上就是“队列”/“双端队列”的尾部索引位)。

而“head”变量和“tail”变量所标识的有效数据范围在不停的变化,甚至有的时候“tail”变量的索引值还会小于“head”变量的索引值——但这丝毫不影响对有效范围的标定。

那么“tail”变量指向数组的最后一个索引位并且进行下一次“添加”操作时,数组就不一定发生“扩容”操作了,而最可能发生的情况就是“tail”变量用重新从当前数组的0号索引位开始,循环利用有效范围外的数组元素存储新的数据。

在ArrayDeque集合中有多组成对出现的操作方法。使用者使用哪一对方法,完全取决于使用者以什么样的结构操作ArrayDeque集合:

  • 将ArrayDeque集合作为队列结构进行使用时:

也就是只允许在ArrayDeque集合的尾部添加数据,在ArrayDeque集合的头部移除或者读取数据时。

方法名 方法意义
add(e) 在队列尾部添加新的元素,新元素不能为null,操作成功后该方法将返回true的标记
offer(e) 该方法效果与add(e)方法一致,都是在队列尾部添加新的元素,新元素不能为null,操作成功后该方法将返回true的标记
remove() 从队列头部移除元素,在集合中没有元素的情况下,会抛出NoSuchElementException异常
poll() 该方法同样从队列头部移除元素,只不过在集合中没有元素的情况下,该方法不会抛出异常,只会返回null
element() 方法试图从队列头部获取元素,但是并不会试图从头部移除这个元素。在集合中没有元素的情况下,会抛出NoSuchElementException异常
peek() 该方法同样试图从队列头部获取元素,同样不会试图从头部移除这个元素。不过在集合中没有元素的情况下,不会抛出异常,只会返回null
  • 将ArrayDeque集合最为双端队列结构使用时:
    ArrayDeque集合实现了java.util.Deque接口,也就是说其可以使用具有双端队列特性的相关操作方式(头部和尾部都可以读写数据):
方法名 方法意义
addLast(e) 在双端队列的尾部添加数据,注意插入的新数据不能为null,否则会抛出NullPointerException异常。
addFirst(e) 在双端队列的头部添加数据,注意插入的新数据不能为null,否则会抛出NullPointerException异常。
offerLast(e) 在双端队列的尾部添加数据,注意插入的新数据不能为null,否则会抛出NullPointerException异常。该方法会在操作完成后返回true
offerFirst(e) 在双端队列的头部添加数据,注意插入的新数据不能为null,否则会抛出NullPointerException异常。该方法会在操作完成后返回true
removeFirst() 该方法在双端队列的头部移除数据,如果当前队列中已没有任何数据可移除,则抛出NoSuchElementException异常
removeLast() 该方法在双端队列的尾部移除数据,如果当前队列中已没有任何数据可移除,则抛出NoSuchElementException异常
pollFirst() 该方法在双端队列的头部移除数据,如果当前队列中已没有任何数据可移除,则返回null
pollLast() 该方法在双端队列的尾部移除数据,如果当前队列中已没有任何数据可移除,则返回null
getFirst() 该方法在双端队列的头部读取数据,但不会移除数据,如果当前队列中已没有任何数据可读取则抛出NoSuchElementException异常
getLast() 该方法在双端队列的尾部读取数据,但不会移除数据,如果当前队列中已没有任何数据可读取则抛出NoSuchElementException异常
peekFirst() 该方法在双端队列的头部读取数据,但不会移除数据,如果当前队列中已没有任何数据可读取则返回null
peekLast() 该方法在双端队列的尾部读取数据,但不会移除数据,如果当前队列中已没有任何数据可读取则返回null
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

说好不能打脸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值