您的位置:首页 > 编程语言 > Java开发

JDK之ArrayDeque源码解析

2017-02-06 16:41 302 查看
刚入java不久的程序猿,对于简单的使用已毫不满足,最终为了一探究竟,翻开了JDK的源码,以下观点为自己的理解及看了多篇博客的总结,欢迎各位大神指出不对的地方,当然也欢迎和我一样刚学的同学,一起加油努力吧~~

ArrayDeque是什么

ArrayDeque是什么?deque英文翻译为双向队列,ArrayDeque就是实现了Deque接口的一个双向队列的集合,ArrayDeque也是由数组实现,数组的任意位置都可以作为头或者尾,ArrayDeque不允许元素为null

ArrayDeque源码解析

在上面我们了解到了ArrayDeque是什么,大致在脑海中留下初步的印象,接下来我们来看一下源码,由于Deque继承了Queue接口,这里我们就先来看下这个接口里定义的方法

public interface Queue<E> extends Collection<E> {
/**
* 插入元素,成功返回true,失败抛出异常
*/
boolean add(E e);

/**
* 插入元素,成功返回true,失败返回false
*/
boolean offer(E e);

/**
* 获取并删除队首元素,队列为空则抛出异常
*/
E remove();

/**
* 获取并删除队首元素,队列为空是返回null
*/
E poll();

/**
* 获取但不删除队首元素,队列为空抛出异常
*/
E element();

/**
* 获取但不删除队首元素,队列为空返回null
*/
E peek();
}


这里的方法已经注释过,大家可以自己看下每个方法的作用,还有就是Queue是继承了Collection接口的,说明最终扔是以迭代的方式来完成的,好了,我们在大致看下Deque接口定义的方法

public interface Deque<E> extends Queue<E> {
/**
* 在队列最前端插入元素,无返回值
*/
void addFirst(E e);

/**
* 在队列最后端插入元素,无返回值
*/
void addLast(E e);

/**
* 在队列最前端插入元素,成功返回true失败返回false
*/
boolean offerFirst(E e);

/**
* 在队列最后端插入元素,成功返回true失败返回false
*/
boolean offerLast(E e);

/**
* 获取并删除队列最前端元素,队列为空抛出异常
*/
E removeFirst();

/**
* 获取并删除队列最后端元素,队列为空抛出异常
*/
E removeLast();

/**
* 获取并删除队列最前端元素,队列为空返回null
*/
E pollFirst();

/**
* 获取并删除队列最后端元素,队列为空返回null
*/
E pollLast();

/**
* 获取但不删除队列最前端元素,队列为空抛出异常
*/
E getFirst();

/**
* 获取但不删除队列最后端元素,队列为空抛出异常
*/
E getLast();

/**
* 获取但不删除队列最前端元素,队列为空返回null
*/
E peekFirst();

/**
* 获取但不删除队列最后端元素,队列为空返回null
*/
E peekLast();

/**
* 删除队列里第一次出现的指定元素
*/
boolean removeFirstOccurrence(Object o);

/**
* 删除队列里最后一次出现的指定元素
*/
boolean removeLastOccurrence(Object o);

// *** Queue methods ***

boolean add(E e);

boolean offer(E e);

E remove();

E poll();

E element();

E peek();

// *** Stack methods ***

/**
* 内存空间允许的情况下,将元素放入出现在栈中的Dqueue中
* 成功返回true,失败抛出异常
*/
void push(E e);

/**
* 删除并返回这个队列的第一个元素
*/
E pop();

// *** Collection methods ***

/**
* 删除某个元素
*/
boolean remove(Object o);

/**
* 是否包含某个元素
*/
boolean contains(Object o);

/**
* 元素数量
*/
public int size();

/**
* 迭代
*/
Iterator<E> iterator();

/**
* 返回一个顺序反转后的迭代器
*/
Iterator<E> descendingIterator();
}


上面就是Deque接口里的方法,看起来方法很多,其实方法无非就是添加,删除,取值,只不过添加删除头部还是尾部以及返回值的不同而已,整个体系看完,接着看最主要的,ArrayDque的源码

public class ArrayDeque<E> extends AbstractCollection<E>
implements Deque<E>, Cloneable, Serializable{
...
}


上面就是ArrayDeque的继承与实现,接下来看一下定义的变量

/**
* 存取队列元素的数组
*/
private transient E[] elements;

/**
* 队列的头
*/
private transient int head;

/**
* 队列的尾
*/
private transient int tail;

/**
* 创建新的队列时最小容量
*/
private static final int MIN_INITIAL_CAPACITY = 8;


这里队列的头与尾,可以说数组中任意位置都可以为头或者尾,继续看代码

/**
* 无参构造,初始化大小为默认大小16
*/
public ArrayDeque() {
elements = (E[]) new Object[16];
}

/**
* 有参构造,参数为元素数量
*/
public ArrayDeque(int numElements) {
allocateElements(numElements);
}

/**
* 有参构造,参数为集合
*/
public ArrayDeque(Collection<? extends E> c) {
allocateElements(c.size());
addAll(c);
}

/**
* 初始化数组
*/
private void allocateElements(int numElements) {
//初始化数组的最小容量
int initialCapacity = MIN_INITIAL_CAPACITY;
//找到大于numElements的最小的2的幂整数
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];
}


上面是ArrayDeque的构造方法,感觉没什么特殊的东西,就是初始化数组,只不过一个是默认的16长度,一个是传入的参数,最后一个构造在初始化数组后,调用AbstractCollection的addAll方法将集合放入,继续看几个比较重要的方法

/**
* 扩容方法,当数组满了进行扩容操作,大小为原来的两倍
*/
private void doubleCapacity() {
assert head == tail;
int p = head;
//元素个数
int n = elements.length;
int r = n - p; // number of elements to the right of p
//将容量扩大一倍
int newCapacity = n << 1;
if (newCapacity < 0)
throw new IllegalStateException("Sorry, deque too big");
Object[] a = new Object[newCapacity];
//数组分为两段复制
System.arraycopy(elements, p, a, 0, r);
System.arraycopy(elements, 0, a, r, p);
elements = (E[])a;
head = 0;
tail = n;
}

/**
* 在队列的前端添加元素,无返回值
*/
public void addFirst(E e) {
if (e == null)
throw new NullPointerException();
elements[head = (head - 1) & (elements.length - 1)] = e;
//判断头尾是否重合,重合即数组满了,需进行扩容
if (head == tail)
doubleCapacity();
}

/**
* 在队列的后端添加元素,无返回值
*/
public void addLast(E e) {
if (e == null)
throw new NullPointerException();
elements[tail] = e;
//判断头尾是否重合,重合即数组满了,需进行扩容
if ( (tail = (tail + 1) & (elements.length - 1)) == head)
doubleCapacity();
}

/**
* 在队列的前端添加元素,调用addFirst方法,返回值true
*/
public boolean offerFirst(E e) {
addFirst(e);
return true;
}

/**
* 在队列的后端添加元素,调用addLast方法,返回值true
*/
public boolean offerLast(E e) {
addLast(e);
return true;
}

/**
* 获取并删除最前端元素
*/
public E removeFirst() {
E x = pollFirst();
//为空时抛出异常
if (x == null)
throw new NoSuchElementException();
return x;
}

/**
* 获取并删除最后端元素
*/
public E removeLast() {
E x = pollLast();
//为空时抛出异常
if (x == null)
throw new NoSuchElementException();
return x;
}

public E pollFirst() {
int h = head;
//队列空为则元素为空
E result = elements[h];
if (result == null)
return null;
//head处置空
elements[h] = null;
//处理特殊情况,当h为elements.length-1时的情况
head = (h + 1) & (elements.length - 1);
return result;
}

public E pollLast() {
//处理特殊情况,当tail为0时的情况
int t = (tail - 1) & (elements.length - 1);
E result = elements[t];
if (result == null)
return null;
elements[t] = null;
//下一个需要添加的下标
tail = t;
return result;
}

/**
* 获取但不删除队列最前端元素
*/
public E getFirst() {
E x = elements[head];
//队列为空抛出异常
if (x == null)
throw new NoSuchElementException();
return x;
}

/**
* 获取但不删除队列最后端元素
*/
public E getLast() {
E x = elements[(tail - 1) & (elements.length - 1)];
//队列为空抛出异常
if (x == null)
throw new NoSuchElementException();
return x;
}

/**
* 获取但不删除队列最前端元素,队列为空返回null
*/
public E peekFirst() {
return elements[head];
}

/**
* 获取但不删除队列最后端元素,队列为空返回null
*/
public E peekLast() {
return elements[(tail - 1) & (elements.length - 1)];
}


好了,这里列出了ArrayDeque最主要的一些方法,其他方法大多都比较简单了,大家可以自己去翻一下源码,最后我们需要注意的是ArrayDeque存元素时,不能存入null元素,否则会报空指针异常,好了,ArrayDeque的解析到这里就结束了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jdk java 源码 博客 集合