java.util.ArrayDeque源码解析
2017-08-11 10:50
363 查看
1.准备知识
因为ArrayDeque使用了循环队列,所以首先要了解循环队列数据结构的原理。http://blog.csdn.net/ya_1249463314/article/details/56013321
2.所属包
package java.util;
3.继承与实现关系
public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, Cloneable, Serializable
4.属性
/** * 存储E类型元素的数组 */ private transient E[] elements; /** * 循环队列的头元素索引 */ private transient int head; /** * 循环队列的尾元素索引 */ private transient int tail; /** * 循环队列的初始化最小容量为8 */ private static final int MIN_INITIAL_CAPACITY = 8;
5.构造方法
构造方法1:/** * 构造一个空的数组循环队列,初始化Object数组长度为16 */ public ArrayDeque() { elements = (E[]) new Object[16]; }
构造方法2:
/** * 构造一个指定长度的数组循环队列 */ public ArrayDeque(int numElements) { allocateElements(numElements); } /** * 分配指定元素长度的Object数组 */ private void allocateElements(int numElements) { int initialCapacity = MIN_INITIAL_CAPACITY; // Find the best power of two to hold elements. // Tests "<=" because arrays aren't kept full. if (numElements >= initialCapacity) { initialCapacity = numElements; initialCapacity |= (initialCapacity >>> 1); initialCapacity |= (initialCapacity >>> 2); initialCapacity |= (initialCapacity >>> 4); initialCapacity |= (initialCapacity >>> 8); initialCapacity |= (initialCapacity >>> 16); initialCapacity++; if (initialCapacity < 0) // Too many elements, must back off initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements } elements = (E[]) new Object[initialCapacity]; }
构造方法3:
/** * 构造一个包含指定 collection 的元素的循环队列 */ public ArrayDeque(Collection<? extends E> c) { //先分配集合c那么长的空间 allocateElements(c.size()); //将c中的元素插入到双端队列中 addAll(c); } /** * 插入集合c中的所有元素,设置标记位modified代表是否插入元素。 * 如果插入元素了就返回标记位为true。 */ public boolean addAll(Collection<? extends E> c) { boolean modified = false; for (E e : c) if (add(e)) modified = true; return modified; } /** * 在队列的尾部插入元素e */ public boolean add(E e) { addLast(e); return true; } /** * */ public void addLast(E e) { //如果插入的元素为空,那么就抛出空指针异常 if (e == null) throw new NullPointerException(); //在队列的尾部插入元素 elements[tail] = e; /** * 按照循环队列的特点,队满时采用(tail+1)%elements.length==head,而在此处使用了与位运算来代替取余运算,由于位运算速度快,所以这种方式效率高。 * 而此处代码的意思是如果循环队列已经达到了队满的状态,那么就进行扩容操作、并且赋值。 */ if ( (tail = (tail + 1) & (elements.length - 1)) == head) doubleCapacity(); } /** * 将队列扩充原来的2倍,并且将元素复制到扩充的数组中。 */ private void doubleCapacity() { assert head == tail; //设置暂时变量p,如果直接操作head,那么就会修改head。而本意是操作head而不修改head。 int p = head; int n = elements.length; //head右边元素的个数 int r = n - p; // number of elements to the right of p //设置新容量,左移一位就相当于扩充为原来的2倍。 int newCapacity = n << 1; //如果新容量的小于0,那么就会抛出非法状态异常。 if (newCapacity < 0) throw new IllegalStateException("Sorry, deque too big"); //创建新容量的Object数组 Object[] a = new Object[newCapacity]; //将elements元素复制到数组a中,从elements数组的p开始,数组a从0开始,复制的长度为r System.arraycopy(elements, p, a, 0, r); //将elements元素复制到数组a中,从elements数组的0开始,数组a从r开始,复制的长度为p System.arraycopy(elements, 0, a, r, p); //将新数组a赋值给elements elements = (E[])a; //然后设置新数组的头索引为0.尾索引为n head = 0; tail = n; }
6.方法
addFirst方法/** * 在队列的头部插入元素e */ public void addFirst(E e) { //如果插入元素为空,那么就抛出空指针异常 if (e == null) throw new NullPointerException(); //与位运算代替取余运算,计算出新的头索引的值,进行插入元素e elements[head = (head - 1) & (elements.length - 1)] = e; //如果头索引和尾索引重合,达到了循环队列的队满状态,就进行扩容赋值操作 if (head == tail) doubleCapacity(); }
remove方法
/** * 获取并移除此双端队列所表示的队列的头。 */ public E remove() { return removeFirst(); } /** * @throws NoSuchElementException {@inheritDoc} */ public E removeFirst() { E x = pollFirst(); if (x == null) throw new NoSuchElementException(); return x; } public E pollFirst() { int h = head; E result = elements[h]; //如果头索引下标对应的元素为空,那么就返回空 if (result == null) return null; //将头索引处的元素设置为空 elements[h] = null; //将头索引对应的空元素,与运算计算出新的索引值 head = (h + 1) & (elements.length - 1); return result; }
7.巧妙设计
(1) ArrayDeque采用循环队列数据结构设计的。(所以增加、删除、判断队空、判断队满都是循环队列的套路)(2) ArrayDeque增加元素,如果循环队列容量不够,那么就扩容为原来的2倍。
(3) ArrayDeque采用与位运算来代替求余运算,提高了效率。(用在判断队满的时候)。
-----------------------------该源码为jdk1.7版本的
相关文章推荐
- 解析java.util集合类源码(Collection和AbstractCollection篇)
- 解析java.util集合类源码(List和AbstractList篇)
- java.util.logging源码解析
- java.util.Stack源码解析
- 【jdk源码解析一】java.util.Observer与java.util.Observable
- Java多线程 -- JUC包源码分析5 -- Condition/ArrayBlockingQueue/LinkedBlockingQueue/Deque/PriorityBlockingQueu
- java.util.concurrent.CountDownLatch控制线程执行工具类源码解析
- java.util.concurrent.CyclicBarrier同步屏障工具类源码解析
- java.util.concurrent包图文源码解析(二)——ReentrantLock
- java.util.concurrent.locks.ReentrantReadWriteLock读写锁源码解析
- 解析java.util集合类源码(ArrayList)
- Java集合(13)——Queue与Deque源码解析
- JDK之ArrayDeque源码解析
- 解析java.util集合类源码(Queue)
- java.util.HashMap源码解析
- 关于java ArrayBlockingQueue 源码解析的小疑惑
- 给jdk写注释系列之jdk1.6容器(11)-Queue之ArrayDeque源码解析
- 解析java.util集合类源码(AbstractList内部类ListIterator和Itr)
- Java源码解析(附录)(4) —— GenericArrayType
- java.util.concurrent.ConcurrentHashMap并发哈希表源码解析