看看ArrayDeque源码

之前看了其他实现Deque接口的类,这里再看看ArrayDeque吧,下图可以看到这个类设计的结构层次,其实Deque接口是继承了Queue接口的。用可调整大小的数组实现Deque接口。没有容量限制,他们根据需要增长以支持使用。它们不是线程安全的,在没有外部同步的情况下,它们不支持多线程的并发访问。禁止使用空元素。

大多数ArrayDeque操作以常量时间运行。例外包括remove,removeFirstOccurrence,removeLastOccurrence,contains,iterator.remove()和一些批量操作,所有这些都以线性时间运行。

此类有三个构造函数,如下图:

ArrayDeque​():构造一个空数组deque,其初始容量16个元素。

ArrayDeque​(int numElements):构造一个空数组deque,其初始容量足以容纳指定数量的元素。

ArrayDeque​(Collection<? extends E> c):按照集合的迭代器返回的顺序构造一个包含指定集合元素的双端队列。

ArrayDeque中的字段主要有 transient Object[] elements,transient int head;,transient int tail;这里看到就是修饰词都是transient,表示类实现了序列化接口,但是该敏感词汇不会被序列化。elements是用来存储元素的;head表示队列的头部,pop()和remove()操作的元素;tail表示下一个元素要添加的位置,比如push(),add()和addLast()要增加的元素。

calculateSize和名字表述一样,用于调整队列容量的使用工具,但是有个限制就是2 ^ 30个元素,注释写的很有趣"good luck"。

还有一种扩容测试是变为原来的两倍,这边如果容量太大,会报“sorry,deque too big”的IllegalStateException异常,可以看到扩容就要复制一份原来的元素,这个还是比较消耗资源的。复制这里用的都是 public static native void arraycopy(Object src,  int  srcPos,Object dest, int destPos,int length);

在此双端队列的前面插入指定的元素,addFirst​(E e)。这里因为是使用数组,所以增加队首元素的时候,需要判断元素在的位置,通过移动head的位置,elements[head = (head - 1) & (elements.length - 1)],这与我们正常看到的队列的第一个元素概念不同。如果head与tail指向了同一个位置,就需要扩容啦。

addLast​(E e):在此双端队列的末尾插入指定的元素。这个与addfist类似,就是要判断队尾的位置,然后是否扩容。

然后我们看看pollFisrt(),将head位置的元素置为空,然后head+1的位置设置为队首,这里借助了一个变量h;后面的pollLast也是类似的,取tail前一个元素的位置。类似的,getFirst()和getLast()也是通过相同的方式,获取元素。

这里判断size和empty的方式也可以看看,size是通过tail和head的差值计算,虽然可能是负数,但是与length-1做了与操作。empty的判断比较简单,就是比较head和tail是否相等。

这里麻烦一点的就是delete操作了,删除某个位置的元素,因为这里按照head和tail的位置,移动tail或者head的位置。

猜你喜欢

转载自my.oschina.net/u/2277632/blog/2907407