Java集合—Stack的源碼深度解析以及應用介紹

  本文對Java中的Stack集合的源碼進行了深度解析,包括各種方法的底層實現,並且給出了Stack的使用建議。

1 Stack的概述

public class Stack< E >
  extends Vector< E >

  Stack,來自於JDK1.0 的古老集合類,底層是數組結構,元素可重複,有序(存放順序),支持下標索引訪問,允許null元素。
  Stack類繼承了Vector,所有方法的實現都是同步的,方法採用了synchronized修飾,數據安全,效率低!。
  Stack針對Vector擴展了五個API方法,主要被用來實現爲先進後出(FILO)的棧。

2 Stack的源碼解析

  由於Stack繼承了Vector類,因此繼承了Vector類的屬性和方法,同時他擴展了Vector類的方法,即新增了五個方法,用於實現先進後出的棧結構。關於Vector集合的介紹,可以看這篇文章:Java的Vector集合源碼深度解析以及應用介紹
  Stack的將底層數組的尾部看成了棧頂,因此入棧時將元素加在尾部,出棧時直接移除尾部的元素,比較簡單,不會導致大量元素位置移動!

2.1 構造器

  僅有一個自己的構造器!用於創建一個空堆棧。

public Stack() {
}

2.2 API方法

  這裏講解相比於Vector新增的將用於實現棧的五個方法!

2.2.1. public E push(E item)

  壓棧:將新元素放在棧頂的位置。新加入的元素把原來的元素往下“壓”,默認最後加入的元素在棧頂。

/**
 * 壓棧(入棧),在內部實現是將元素放在內部數組的末尾
 * @param item 添加的元素
 * @return 被添加的元素
 */
public E push(E item) {
    //調用了父類的addElement方法,將元素放在內部數組的末尾
    addElement(item);
    //返回被添加的元素
    return item;
}

2.2.2 public E peek()

  獲得棧頂元素,但是不移除。如果棧爲空,將拋出EmptyStackException異常。

/**
 * 獲取棧頂元素但不移除
 * @return 棧頂元素
 */
public synchronized E peek() {
    //獲取元素數量
    int     len = size();
    //如果數量等於0則說明是空棧,拋出異常
    if (len == 0)
        throw new EmptyStackException();
    //返回內部數組的尾部元素
    return elementAt(len - 1);
}

2.2.3 public E pop()

  獲得棧頂,並移除(彈棧)。如果棧爲空,將拋出EmptyStackException異常。

/**
 * 獲取棧頂元素並不移除
 * @return 棧頂元素
 */
public synchronized E pop() {
    E       obj;
    //獲取元素數量
    int     len = size();
    //獲取棧頂元素但不移除
    obj = peek();
    //移除底層數組尾部元素
    removeElementAt(len - 1);
    //返回被出棧的元素
    return obj;
}

2.2.4 public boolean empty()

  判斷棧容器是否爲空棧。

public boolean empty() {
    //很簡單,直接看元素數量是否等於0
    return size() == 0;
}

2.2.5 public int search(Object o)

  搜索o在棧空間當中的位置:以1爲基礎,從棧頂開始計算,返回值爲-1時表示此對象不在堆棧中。底層使用 equals 方法比較 o 與堆棧中的項。

/**
 * 搜索o在棧空間當中的位置:以1爲基礎,從棧頂開始計算,返回值爲-1時表示此對象不在堆棧中。底層使用 equals 方法比較 o 與堆棧中的項。
 * @param o 搜索的元素
 * @return 位置
 */
public synchronized int search(Object o) {
    //從尾部倒序向頭部搜索索引位置,返回第一個被找到的元素的索引,沒找到返回-1
    int i = lastIndexOf(o);
    //如果位置i大於等於0,則返回size-i;
    //即如果size=5,i=4,那麼該元素在"棧"結構中的位置因該是1,即以1爲基礎,棧頂元素位置就是1
    if (i >= 0) {
        return size() - i;
    }
    //沒找到就返回-1
    return -1;
}

2.2.6 案例

public class StackDemo01 {

    public static void main(String[] args) {
        Stack<String> s = new Stack<>();
        s.push("a");
        s.push("b");
        s.push("c");
        s.push("d");
        while (!s.empty()) {
            String pop = s.pop();
            System.out.print(pop + " ");
        }
    }
}

3 總結

  Stack類的實現還是很簡單的,相比父類Vector就是多了五個方法。但是由於來自於JDK1.0,那時候的集合都很原始並且使用Synchronized修飾,性能可能不是很好,並且底層實現比較粗糙!
  在JDK1.6的時候,添加了集合類ArrayDeque,該類實現了Deque接口,即作爲一個“雙端隊列”,可以被用來實現Stack(棧)或者Queue(隊列)。
  ArrayDeque內部是採用可變數組實現的雙端隊列,採用兩個外部引用來保持隊列頭結點和尾節點的訪問,同時刪除隊列頭尾元素時不會移動其他元素,而是移動引用的位置,即形成一個環形隊列,能夠複用數組空間(允許隊頭索引比隊尾索引值更大),相比於另外一個使用鏈表實現的雙端隊列LinkedList綜合效率更好(LinkedList介紹:Java的LinkedList集合源碼深度解析以及應用介紹)!同時,如果用於實現棧,那麼相比於Stack的綜合效率同樣更好!不過ArrayDeque不支持null元素,並且不是線程安全的!
  因此,JDK推薦我們一般使用ArrayDeque來替代Stack實現棧!
  同時如果你真的想了解JVM的棧空間的工作過程,可以看看這篇文章:Java的JVM運行時棧結構和方法調用詳解,看完你會發現爲什麼上面的集合可以用來模擬“棧空間”了,因爲方法在棧空間中的調用也是“先進後出”的!
  我們後續將會介紹的更多集合,比如TreeMap、HashMap,LinkedHashMap、HashSet、TreeSet、ArrayDeque等基本集合以及JUC包中的高級併發集合。如果想學習集合源碼的關注我的專欄更新!

如果有什麼不懂或者需要交流,可以留言。另外希望點贊、收藏、關注,我將不間斷更新各種Java學習博客!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章