首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Stack 深度解析:基於 Vector 的 LIFO 棧實現與使用指南

     編輯:Java 相關知識

java.util.Stack 是 JDK 1.0 即提供的經典後進先出(LIFO)棧實現。雖然官方文檔建議優先使用 ArrayDeque,但在維護遺留代碼、理解棧原理、特定場景下仍具參考價值。本文從繼承體系、源碼實現、API 詳解到實戰示例全方位剖析。

一、類繼承與定位

java.lang.Object
  java.util.AbstractCollection<E>
    java.util.AbstractList<E>
      java.util.Vector<E>
        java.util.Stack<E>

public class Stack<E> extends Vector<E> { }
  • 繼承 Vector → 底層動態數組存儲,而非鏈表。
  • 繼承所有 Vector 方法(含同步機制),並額外提供 5 個棧專用 API。
  • 線程安全(方法級 synchronized),但同步粒度粗、性能一般。

二、棧專用 API 速查

方法簽名語義異常情況
pushE push(E item)壓入棧頂(數組末尾),返回 item無
popsynchronized E pop()彈出棧頂並移除,返回元素空棧拋 EmptyStackException
peeksynchronized E peek()查看棧頂不移除,返回元素空棧拋 EmptyStackException
emptyboolean empty()判斷棧是否為空無
searchsynchronized int search(Object o)從棧底向頂查找,返回 1-based 位置未找到返回 -1

三、源碼核心邏輯(JDK 8)

public class Stack<E> extends Vector<E> {
    private static final long serialVersionUID = 1224463164541339165L;

    public Stack() { }  // 唯一構造函數,委託 Vector()

    // 壓棧:委託 Vector.addElement() → 數組末尾追加
    public E push(E item) {
        addElement(item);
        return item;
    }

    // 彈棧:同步獲取棧頂 → 同步移除最後一個元素
    public synchronized E pop() {
        E obj;
        int len = size();
        obj = peek();                 // 拋空棧異常
        removeElementAt(len - 1);     // 刪除數組最後一位
        return obj;
    }

    // 查看棧頂:同步返回數組最後一個元素
    public synchronized E peek() {
        int len = size();
        if (len == 0) throw new EmptyStackException();
        return elementAt(len - 1);
    }

    public boolean empty() {
        return size() == 0;
    }

    // 搜索:從棧底向頂,返回 1-based 索引
    public synchronized int search(Object o) {
        int i = lastIndexOf(o);  // Vector 從尾向頭找
        if (i >= 0) return size() - i;
        return -1;
    }
}

關鍵點總結

  1. 數組末尾即棧頂:push = addElement(尾部追加),pop/peek = 操作 elementData[size-1]。
  2. 同步粒度:pop/peek/search 加 synchronized,push/empty 依賴父類同步方法。
  3. search 語義特殊:返回「距離棧頂的 1-based 距離」,非標準索引。

四、實戰示例

import java.util.*;

public class StackDemo {
    public static void main(String[] args) {
        Stack<String> stack = new Stack<>();

        // 壓入 1~5
        for (int i = 1; i <= 5; i++) stack.push(String.valueOf(i));
        System.out.println("初始棧(底→頂): " + stack);  // [1, 2, 3, 4, 5]

        // 搜索位置
        System.out.println("元素 '2' 位置: " + stack.search("2"));  // 4 (頂→底第4個)

        // 彈出棧頂
        System.out.println("pop: " + stack.pop());  // 5
        printStack(stack);

        // 查看棧頂
        System.out.println("peek: " + stack.peek());  // 4
        printStack(stack);

        // 兩種遍歷方式
        System.out.println("\n--- 隨機訪問遍歷 ---");
        iteratorRandomAccess(stack);

        System.out.println("\n--- Iterator 遍歷 ---");
        iteratorIterator(stack);
    }

    static void printStack(Stack<String> s) {
        System.out.print("當前棧: ");
        for (int i = 0; i < s.size(); i++) System.out.print(s.get(i) + " ");
        System.out.println();
    }

    static void iteratorRandomAccess(List<String> list) {
        for (int i = 0; i < list.size(); i++) System.out.print(list.get(i) + " ");
        System.out.println();
    }

    static void iteratorIterator(List<String> list) {
        for (Iterator<String> it = list.iterator(); it.hasNext(); )
            System.out.print(it.next() + " ");
        System.out.println();
    }
}

五、Stack vs ArrayDeque:為何官方推薦後者

維度StackArrayDeque
底層結構動態數組(繼承 Vector)循環數組(雙端隊列)
線程安全同步方法(粗粒度鎖)非線程安全(高性能)
擴容機制1.5 倍/2 倍(Vector 策略)2 倍,無同步開銷
功能豐富度僅 LIFO 棧雙端隊列、棧、隊列通用
Null 元素允許不允許
推薦場景遺留代碼、教學演示所有新代碼棧/隊列需求
最佳實踐:
// 新代碼首選
Deque<String> stack = new ArrayDeque<>();
stack.push("a");
stack.pop();
stack.peek();
  • 單線程高性能棧 → ArrayDeque。
  • 多線程併發棧 → ConcurrentLinkedDeque 或加鎖 ArrayDeque。
  • 僅維護舊代碼時接觸 Stack,理解其同步與數組特性即可。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved