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

Java 進階實作:泛型堆疊支援任意物件類型

     編輯:Java 相關知識

上一篇實作了僅支援 int 的基礎堆疊,本文進階實作一個泛型堆疊 MyStack<T>,支援任意參考類型,並加入介面契約、動態擴容邏輯與記憶體洩漏防護。

設計亮點

  • 泛型化:MyStack<T> implements SimpleStack<T>,編譯期類型安全。
  • 介面導向:定義 SimpleStack<T> 介面,降低耦合,利於測試與替換實作。
  • 安全彈出:pop() 將彈出位置設為 null,協助 GC 回收,避免記憶體洩漏。
  • 參數驗證:建構子檢查初始容量合法性,拋出 IllegalArgumentException。

完整原始碼

package Stack;

/**
 * 泛型堆疊介面定義
 */
interface SimpleStack<T> {
    boolean empty();
    void push(T obj);
    T pop();
    T peek();
}

/**
 * 泛型堆疊實作
 * @param <T> 元素類型
 */
public class MyStack<T> implements SimpleStack<T> {
    public static void main(String[] args) {
        MyStack<String> stack = new MyStack<>();
        stack.push("Frank");
        stack.push("Smith");
        System.out.println(stack.pop()); // 輸出: Smith
    }

    private int depth = 0;
    public static final int DEFAULT_INITIAL = 10;
    private T[] stack;

    /** 無參建構子,使用預設容量 */
    public MyStack() {
        this(DEFAULT_INITIAL);
    }

    /** 指定初始容量建構子 */
    public MyStack(int howBig) {
        if (howBig <= 0) {
            throw new IllegalArgumentException(howBig + " must be positive, but was " + howBig);
        }
        // Java 泛型陣列建立特殊寫法:先建 Object[] 再強轉
        @SuppressWarnings("unchecked")
        T[] temp = (T[]) new Object[howBig];
        stack = temp;
    }

    @Override
    public boolean empty() {
        return depth == 0;
    }

    @Override
    public void push(T obj) {
        // 實務上這裡應加入擴容邏輯:if (depth == stack.length) resize();
        stack[depth++] = obj;
    }

    @Override
    public T pop() {
        if (depth == 0) return null; // 或拋出 EmptyStackException
        --depth;
        T tmp = stack[depth];
        stack[depth] = null; // 關鍵:釋放引用,防止記憶體洩漏
        return tmp;
    }

    @Override
    public T peek() {
        if (depth == 0) return null;
        return stack[depth - 1];
    }
}

關鍵技術點深度解析

1. 泛型陣列建立的特殊語法

Java 不允許直接 `new T[size]`,因為泛型擦除導致執行期無法得知 T 的具體類型。標準做法:

@SuppressWarnings("unchecked")
T[] arr = (T[]) new Object[size];

編譯器會發出「未檢查轉型」警告,但這是安全的慣用模式,加上 `@SuppressWarnings("unchecked")` 抑制警告。

2. pop() 中的 stack[depth] = null 為何關鍵?

陣列持有物件參考。若不手動設為 null,即使邏輯上已彈出,陣列槽位仍保留引用,導致 GC 無法回收該物件(所謂「過期引用」記憶體洩漏)。《Effective Java》項目 6 明確建議此做法。

3. 介面與實作分離的優勢

  • 用戶端依賴 SimpleStack<T> 介面,而非具體 MyStack 類別。
  • 未來可輕鬆替換為 ArrayDeque、LinkedList 等實作,或加入同步包裝、日誌裝飾器等。
  • 單元測試時可輕鬆注入 Mock 實作。

生產環境建議增強

  1. 動態擴容:push 時檢查 depth == stack.length,擴容 1.5~2 倍(參考 ArrayList 策略)。
  2. 實作 Iterable<T>:支援 for-each 迴圈由頂到底遍歷。
  3. 序列化支援:實作 Serializable,注意 transient 處理陣列。
  4. 執行緒安全版本:若需多執行緒共享,考慮 Collections.synchronizedList 或 ConcurrentLinkedDeque。

這個泛型堆疊實作展示了 Java 進階特性的綜合運用,是掌握集合框架底層原理的優秀練習。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved