java進階|java隊列源碼分析

今天我要分享的是java裏面比較常見的數據結構隊列的源碼分析,隊列,先進先出模式,即FIFO的特色,平常生活中隊列的特色也隨處可見,超市購物排隊,餐廳排隊買飯等一系列都知足了隊列的先進先出的特色,java做爲一門高級語言,天然提供了隊列這種成熟的數據結構供咱們使用了。
java

 

今天我就以本身的理解進行分析了,首先先說下或者先講述下我爲何要寫這篇文章吧?工做中用到了?沒有,那你爲何要寫?炫技?也不是,主要是以前我本身分析了ArrayList,LinkedList以及Stack的源碼文章了,到這裏就理所應當的應該分析隊列的這種數據結構了,知足一下學生時代心心念的數據結構吧。nginx

  

數據結構,數組,鏈表,棧,隊列等在咱們的開發中很常見,可是我沒有用隊列的特色作過業務的需求開發,因此這篇文章的講述天然就涉及不到工做的內容了。面試


說了這麼多,接下來就逐漸去分析隊列的源碼吧,寫到這時下起了小雨,對,這個時間段是晚上十點左右,這篇文章是本身繼五一放假來的第一篇文章,本身玩着玩着手機就忽然想起了要寫這篇文章了,索性就過來寫了,要是學生時代這麼努力多好,其實我不後悔學生時期的貪玩,即便那個時間段努力增進本身的技術又能怎樣?誰也不知道將來會怎樣,不後悔,便值得。數據庫


關於讀源碼,如何進行梳理整個過程,每一個人都有着本身的一套,在這裏我就以本身的一套來進行分析好了。絮叨了這麼多,接下來就是示例程序的展現了,今天看了一位做者的說法,他說寫一篇文章,代碼不易過多,每一個人都有着本身的寫做方式,見仁見智吧,適合本身的纔是最好的,好懷念寫代碼的那段日子,沒日沒夜。數組


這裏要分析的是下面這個隊列,因此這裏暫時下貼出一點這個類的繼承結構,便於本身分析。
微信

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

一,首先咱們先看下ArrayDequeue隊列的構造函數吧。
數據結構

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

構造一個內存容量爲16大小的數組,用於存儲數據元素,即隊列的初始大小容量爲16,能夠容納16個數據元素。
jvm

二,ArrayDequeue也支持自定義容量的構造函數的設置,和ArrayList集合差很少的意思,這樣減小了數組元素的拷貝,提升了性能,通常面試的時候都會問到這一點的。
函數

 public ArrayDeque(int numElements) { allocateElements(numElements); }  步驟一: private void allocateElements(int numElements) {        int initialCapacity = MIN_INITIAL_CAPACITY; if (numElements >= initialCapacity) { initialCapacity = numElements; initialCapacity |= (initialCapacity >>> 1); initialCapacity |= (initialCapacity >>> 2); initialCapacity |= (initialCapacity >>> 4); initialCapacity |= (initialCapacity >>> 8); initialCapacity |= (initialCapacity >>> 16); initialCapacity++;
if (initialCapacity < 0) initialCapacity >>>= 1; }        elements = new Object[initialCapacity];//暫時先看這部分好了,就是內存空間的開闢,上面的內容暫時先不理解也沒事,不影響咱們的分析

寫到這裏,寫到了內存空間的分配的字樣,想到了本身學習c語言的模樣,那個拿着大部書《C語言程序設計》前往機房的少年,因爲興趣使然,逐漸走上了javaWeb的開發了,不過這裏說明一點,學習c語言對於你理解高級語言java大有裨益,這是本身的理解。
源碼分析


三,通常寫到這裏就會去分析數據結構的基本方法,添加方法add了,這裏固然是順勢而爲分析一下add方法了。

 public boolean add(E e) { addLast(e); return true;    } 步驟一:public void addLast(E e) { if (e == null) throw new NullPointerException(); elements[tail] = e; if ( (tail = (tail + 1) & (elements.length - 1)) == head) doubleCapacity();

首先進行前置校驗,判斷元素e是否爲null,如果null直接拋出空指針異常,提及前置校驗,其實你在作javaWeb的開發時必定會遇到的,基於aop的方式或者手動判斷都是要的,由於咱們要去校驗不可信數據即外部輸入的數據,關於如何校驗,這裏暫時說一下,本身後面會單獨寫上一篇關於參數校驗的文章了,而後將元素e放置到數據的末尾,而後判斷隊列是否滿了,若滿了則進行擴容,這也是爲何叫動態擴容機制了,如今誰還在使用靜態擴容呢?況且java做爲一門高級語言呢,順勢而爲成就了這個語言使人喜歡的特色吧。


四,隊列既然有入隊,想必就會想到隊列出隊的方法,即poll方法,接下來咱們繼續看下隊列出隊的方法時間吧。

 public E poll() { return pollFirst(); }  步驟一:  public E pollFirst() { int h = head; @SuppressWarnings("unchecked") E result = (E) elements[h]; // Element is null if deque empty if (result == null) return null; elements[h] = null; // Must null out slot head = (h + 1) & (elements.length - 1); return result;

首先將隊頭元素賦值給局部變量h,即int h=head,這也是一向寫代碼的習慣,而後根據數組下標值進行元素的定位,即時間複雜度爲O(1)這也是數組做爲查找比較快的緣由之一吧,寫到這寫到了hash函數的特性了,時間複雜度也很小,後面如果有須要能夠分享一下關於hash相關的內容,畢竟數據結構map的特色就是結合hash加上樹,鏈表,數組組成了優秀的源碼。而後將隊列的隊頭元素置爲null,這樣便於垃圾收集器進行資源的回收,可是這裏沒有寫到let's gc ,怎麼和集合不同呢,而後隊列元素前置一位,而且判斷隊列是否在整個隊列的範圍內,這是比較重要的,將獲取的元素進行返回。


五,有了入隊,出隊,接下來咱們在看下如何獲取元素個數

public int size() { return (tail - head) & (elements.length - 1); }

    隊尾元素位置減去隊首元素位置進行隊列元素個數的肯定,是否是很簡單,寫到這是否是有點激動能夠寫本身的隊列了,其實造輪子當然使人興奮,可是爲時尚早,慢慢來,須要的時候天然要造輪子的。


六,通常集合都會有判空操做,否則在操做元素時發現是空的,也沒有什麼意義了,這也是算前置校驗的一種吧。

public boolean isEmpty() { return head == tail; }

隊首位置等於隊尾位置就表示這個隊列爲空,是否是很容易理解。


七,通常集合數據結構咱們都會去判斷某個元素是否存在,這樣便於咱們的查找,說到這沒有數據庫咱們同樣能夠去操做數據,不過都是基於內存來操做的,數據庫的出現能夠將數據永遠存儲到存儲介質中,保證了斷電不易丟失的特性,這也是它普遍的用途吧。

public boolean contains(Object o) { if (o == null) return false; int mask = elements.length - 1; int i = head; Object x; while ( (x = elements[i]) != null) { if (o.equals(x)) return true; i = (i + 1) & mask; } return false; }

首先,先將元素元素o與null進行比對,若爲null則直接返回false,由於隊列不容許添加元素爲null的值,因此這裏又作了一下前置校驗,加快校驗的速度,而後循環判斷元素o和隊列的每個元素進行比較,此時時間複雜度爲O(n),相等則返回true,不然返回false。


八,隊列這個數據結構能夠像棧同樣只返回隊列的隊首元素,可是不出隊。

public E peek() { return peekFirst(); }  步驟一:  public E peekFirst() { // elements[head] is null if deque empty return (E) elements[head]; }

這裏只返回數組的第一個元素,可是不出隊,是否是很巧妙,這是設計的構思,欣賞一下。


九,隊列的操做其實也是增刪改查操做,這裏介紹最後一個方法,如何清空隊列的元素。

 public void clear() { int h = head; int t = tail; if (h != t) { // clear all cells head = tail = 0; int i = h; int mask = elements.length - 1; do { elements[i] = null; i = (i + 1) & mask; } while (i != t); } }

首先使用兩個局部變量h,t進行隊首,隊尾元素位置的肯定,使用do...while語句進行判斷隊首是否等於隊尾來判斷隊列是否爲空,而後將數組的每個元素置爲null,而後等jvm垃圾收集器進行收集元素爲null,這樣隊列的元素就被清空了。


十,到這裏就結束了本身對隊列的源碼分析,其實你會發現我這裏沒有對隊列的每個方法進行分析,其實都差很少,這裏起到一個開頭做用就能夠了,下面的每一個分析方法都差很少。


時間也不早了,也快到晚上十一點了,到這裏就結束了,本身寫文章的風格漸漸變了,變得文字稍微多了一點。

本文分享自微信公衆號 - WwpwW()。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索