剛入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的解析到這裏就結束了