java stack的詳細實現分析

來源:互聯網
上載者:User
簡介

    我們最常用的資料結構之一大概就是stack了。在實際的程式執行,方法調用的過程中都離不開stack。那麼,在一個成熟的類庫裡面,它的實現是怎麼樣的呢。也許平時我們實踐的時候也會嘗試著去寫一個stack的實現玩玩。這裡,我們就仔細的分析一下jdk裡的詳細實現。 Stack

    如果我們去查jdk的文檔,我們會發現stack是在Java.util這個包裡。它對應的一個大致的類別關係圖如下:

    通過繼承Vector類,Stack類可以很容易的實現他本身的功能。因為大部分的功能在Vector裡面已經提供支援了。

Stack裡面主要實現的有一下幾個方法:

方法名 傳回型別 說明
empty boolean 判斷stack是否為空白。
peek E 返回棧頂端的元素。
pop E 彈出棧頂的元素
push E 將元素壓入棧
search int 返回最靠近頂端的目標元素到頂端的距離。

    因為前面我們已經提到過,通過繼承Vector,很大一部分功能的實現就由Vector涵蓋了。Vector的詳細實現我們會在後面分析。它實現了很多的輔助方法,給Stack的實現帶來很大的便利。現在,我們按照自己的思路來分析每個方法的具體步驟,再和具體實現代碼對比。 empty

    從我們的思路來說,如果要判斷stack是否為空白,就需要有一個變數來計算當前棧的長度,如果該變數為0,則表示該棧為空白。或者說我們有一個指向棧頂的變數,如果它開始的時候是設定為空白的,我們可以認為棧為空白。這部分的實現代碼也很簡單: Java代碼   public boolean empty() {       return size() == 0;   }  

 如果更進一步分析的話,是因為Vector已經實現了size()方法。在Vector裡面有一個變數elementCount來表示容器裡元素的個數。如果為0,則表示容器空。這部分在Vector裡面的實現如下: Java代碼   public synchronized int size() {       return elementCount;   }  

  peek

    peek是指的返回棧頂端的元素,我們對棧本身不做任何的改動。如果棧裡有元素的話,我們就返回最頂端的那個。而該元素的索引為棧的長度。如果棧為空白的話,則要拋出異常: Java代碼   public synchronized E peek() {       int     len = size();          if (len == 0)           throw new EmptyStackException();       return elementAt(len - 1);   }  

 這個elementAt方法也是Vector裡面的一個實現。在Vector裡面,實際上是用一個elementData的Object數組來儲存元素的。所以要找到頂端的元素無非就是訪問棧最上面的那個索引。它的詳細實現如下: Java代碼   public synchronized E elementAt(int index) {       if (index >= elementCount) {           throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);       }          return elementData(index);   }      @SuppressWarnings("unchecked")   E elementData(int index) {       return (E) elementData[index];   }   pop

    pop方法就是將棧頂的元素彈出來,如果棧裡有元素,就取最頂端的那個,否則就要拋出異常: Java代碼   public synchronized E pop() {       E       obj;       int     len = size();          obj = peek();       removeElementAt(len - 1);          return obj;   }  

    在這裡,判斷是否可以取棧頂元素在peek方法裡實現了,也將如果棧為空白則拋異常的部分包含在peek方法裡面。這裡有必要注意的一個細節就是,在通過peek()取到頂端的元素之後,我們需要用removeElementAt()方法將最頂端的元素移除。我們平時可能不太會留意到這一點。為什麼要移除呢。我們反正有一個elementCount來記錄棧的長度,不管它不是也可以嗎。

    實際上,這麼做在程式啟動並執行時候會有一個潛在的記憶體泄露的問題。因為在java裡面,如果我們普通定義的類型屬於強參考型別。比如這裡vector就底層用的Object[]這個數組強型別來儲存資料。強型別在jvm中做gc的時候,只要程式中有引用到它,它是不會被回收的。這就意味著在這裡,只要我們一直在用著stack,那麼stack裡面所有關聯的元素就都別想釋放了。這樣已耗用時間一長就會導致記憶體泄露的問題。那麼,為瞭解決這個問題,這裡就是用的removeElementAt()方法。

  Java代碼   public synchronized void removeElementAt(int index) {       modCount++;       if (index >= elementCount) {           throw new ArrayIndexOutOfBoundsException(index + " >= " +                                                    elementCount);           }       else if (index < 0) {           throw new ArrayIndexOutOfBoundsException(index);       }       int j = elementCount - index - 1;       if (j > 0) {           System.arraycopy(elementData, index + 1, elementData, index, j);       }       elementCount--;       elementData[elementCount] = null; /* to let gc do its work */  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.