Jdk1.8 Collections Framework源碼解析(3)-ArrayDeque

表、棧和隊列是三種基本的數據結構,前面總結的ArrayList和LinkedList能夠做爲任意一種數據結構來使用,固然因爲實現方式的不一樣,操做的效率也會不一樣。 這篇要看一下java.util.ArrayDeque。從命名上看,它是一個由數組實現的雙端隊列。仍是先看一下它實現了哪些接口。java

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

在看看它的類註釋,做者是 大名鼎鼎的 Doug Lea, 大師級的人物,鄙人只能膜拜。上面balbala , biu biu biu ...... 的一大竄,大致是說,java.util.ArrayDeque是Deque接口的動態數組實現,容量會按需擴展,線程不安全。做爲棧使用比java.util.Stack快,做爲隊列使用比java.util.LinkedList快。大多數的操做消耗常數時間。主要特性就是這些。數組

在看源碼的時候,仍是老規矩,若是是你來作的話,你會如何來實現呢?首先,按照註釋的來,確定是要有個數組來保存數據啦,沒啥好說的。既然是雙端的隊列,必然有一個前,一個後的指針分別指向首尾。既然是一個數組,那麼優點就是在查找上,指針移動的速度就會很快,能夠快速的查找到元素的位置。總體的想法大概就是這樣。 那麼接下來,咱們來看看java.util.ArrayDeque的源碼吧。具體的源碼的實現。安全

/**
     * The array in which the elements of the deque are stored.
     * The capacity of the deque is the length of this array, which is
     * always a power of two. The array is never allowed to become
     * full, except transiently within an addX method where it is
     * resized (see doubleCapacity) immediately upon becoming full,
     * thus avoiding head and tail wrapping around to equal each
     * other.  We also guarantee that all array cells not holding
     * deque elements are always null.
     */
    private transient E[] elements;

    /**
     * The index of the element at the head of the deque (which is the
     * element that would be removed by remove() or pop()); or an
     * arbitrary number equal to tail if the deque is empty.
     */
    private transient int head;

    /**
     * The index at which the next element would be added to the tail
     * of the deque (via addLast(E), add(E), or push(E)).
     */
    private transient int tail;

    /**
     * The minimum capacity that we'll use for a newly created deque.
     * Must be a power of 2.
     */
    private static final int MIN_INITIAL_CAPACITY = 8;

能夠看到,基本上是這樣。最後一個常量表示初始化的最小容量,註釋說明這個值必須是2的冪,這是爲何??, 源碼註釋是這樣說的,不知道爲啥, 先記住這個問題,繼續往下看。數據結構

/**
     * Constructs an empty array deque with an initial capacity
     * sufficient to hold 16 elements.
     */
    public ArrayDeque() {
        elements = (E[]) new Object[16];
    }

    /**
     * Constructs an empty array deque with an initial capacity
     * sufficient to hold the specified number of elements.
     *
     * @param numElements  lower bound on initial capacity of the deque
     */
    public ArrayDeque(int numElements) {
        allocateElements(numElements);
    }

    /**
     * Constructs a deque containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.  (The first element returned by the collection's
     * iterator becomes the first element, or <i>front</i> of the
     * deque.)
     *
     * @param c the collection whose elements are to be placed into the deque
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayDeque(Collection<? extends E> c) {
        allocateElements(c.size());
        addAll(c);
    }

關注一些註釋,一共有3個構造方法。無參的構造方法會建立長度爲16的內部數組。接受一個集合的構造方法不用多說了,看一下接受「元素數量」的構造方法,裏面會調一個分配內部數組空間的方法。app

/**
     * Allocate empty array to hold the given number of elements.
     *
     * @param numElements  the number of elements to hold
     */
    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];
    }

這個方法是根據給定numElements來進行內部數組空間的分配。這裏有一個前提,容量必須是2的冪,儘管如今還不知道爲何必須是2的冪,但先往下看。能夠看到若是numElements小於最小容量8的話,就會按最小容量來分配數組空間。若是大於等於8,會到一個條件語句中作一些操做,看下這些操做是幹嗎的。咱們知道若是一個2進制數是2的冪,那麼它的特色就是隻有一位是1。this

2^0 = 1  
2^1 = 10  
2^n = 10000...(n個0)
2^1 = 1 + 1  
2^3 = 111 + 1  
2^n = 111...(n個1) + 1
相關文章
相關標籤/搜索