天天看點

為什麼 java.util.Stack不被官方所推薦使用!

Java 為什麼不推薦使用 Stack 呢?

  因為 Stack 是 JDK 1.0 的産物。它繼承自 Vector,Vector 都不被推薦使用了,你說 Stack 還會被推薦嗎?

  當初 JDK1.0 在開發時,可能為了快速的推出一些基本的資料結構操作,是以推出了一些比較粗糙的類。比如,Vector、Stack、Hashtable等。這些類中的一些方法加上了 synchronized 關鍵字,容易給一些初級程式員在使用上造成一些誤解!而且在之前的幾個版本中,性能還不怎麼好。

  基于 Vector 實作的棧 Stack。底層實際上還是數組,是以還是存在需要擴容。Vector 是由數組實作的集合類,它包含了大量集合處理的方法。而 Stack 之是以繼承 Vector,是為了複用 Vector 中的方法,來實作進棧(push)、出棧(pop)等操作。這裡就是 Stack 設計不好的地方,既然隻是為了實作棧,不用連結清單來單獨實作,而是為了複用簡單的方法而迫使它繼承 Vector,Stack 和 Vector 本來是毫無關系的。這使得 Stack 在基于數組實作上效率受影響,另外因為繼承 Vector 類,Stack 可以複用 Vector 大量方法,這使得 Stack 在設計上不嚴謹。

  Java 提供了 Deuqe。Deque 是繼承自 Queue,而 Stack 是繼承自 Vector。Java 中的 Deuqe,即“double ended queue”的縮寫,是 Java 中的雙端隊列集合類型。Deque 具備普通隊列 FIFO 的功能,同時它也具備了 Stack 的 LIFO 功能,并且保留了 push 和 pop 函數,是以使用起來應該是一點障礙都沒有。

  ArrayDeque 是 Deque 接口的一種具體實作,是依賴于可變數組來實作的。ArrayDeque 沒有容量限制,可根據需求自動進行擴容。ArrayDeque 可以作為棧來使用,效率要高于 Stack。ArrayDeque 也可以作為隊列來使用,效率相較于基于雙向連結清單的 LinkedList 也要更好一些。注意,ArrayDeque 不支援為 null 的元素。

原文連結:https://www.xttblog.com/?p=3416

關于java.util.stack的底層實作

當push一個元素時:

public E push(E item) {
    addElement(item);
    return item;
}
           

實際上調用但是Vector的addElement方法

public synchronized void addElement(E obj) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = obj;
}
           

而Vector的底層實作就是一個數組,初始大小為10,每當元素超出就增長為原來的2倍,和ArrayList的增長方式類似。

public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
    protected Object[] elementData;
    public Vector() {
      //初始大小為10
    this(10);
    }
    public Vector(int initialCapacity) {
    this(initialCapacity, 0);
    }
    public Vector(int initialCapacity, int capacityIncrement) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
        //初始化為10
    this.elementData = new Object[initialCapacity];
    this.capacityIncrement = capacityIncrement;
	……
 }
           

  總結:在java.util.stack中,棧的底層是使用數組來實作的,數組初始大小為10。每當元素個數超出數組容量就擴充為原來的2倍,将原數組中的元素拷貝到新數組中,随着數組元素的增多,這種開銷也越大。

​ Java并不推薦使用java.util.stack來進行棧的操作,而是推薦使用一個雙端隊列“deque ”來代替它。

關于“deque”

public interface Deque<E>extends Queue<E>
           

  它是一個線性 collection,支援在兩端插入和移除元素。名稱 deque 是“double ended queue(雙端隊列)”的縮寫,通常讀為“deck”。大多數 Deque 實作對于它們能夠包含的元素數沒有固定限制,但此接口既支援有容量限制的雙端隊列,也支援沒有固定大小限制的雙端隊列。

  此接口定義在雙端隊列兩端通路元素的方法。提供插入、移除和檢查元素的方法。每種方法都存在兩種形式:一種形式在操作失敗時抛出異常,另一種形式傳回一個特殊值(null 或 false,具體取決于操作)。插入操作的後一種形式是專為使用有容量限制的 Deque 實作設計的;在大多數實作中,插入操作不能失敗。

  雙端隊列也可用作 LIFO(後進先出)堆棧。應優先使用此接口而不是遺留 Stack 類。在将雙端隊列用作堆棧時,元素被推入雙端隊列的開頭并從雙端隊列開頭彈出。堆棧方法完全等效于 Deque 方法