Stack In Java——對java中棧使用的一些思考

棧的介紹

棧(Stack)是一種後入先出(LIFO)的數據結構。經常用來形象說明棧的結構的例子是書箱:把書平放到書箱裏,先取出來的書是最後放進去的。

應該使用Stack類嗎?

相信大多數人(也包括我),在調用Java中封裝好的數據結構以在代碼中使用棧結構時,往往使用java.util.Stack類。

// import java.util.*;

	Stack<Integer> stack = new Stack<>();
    stack.push(1);
    while (!stack.empty()){
    	System.out.println(stack.pop());
    }

這難道不是很正常嗎?就像使用集合時調用Set,使用列表時調用List一樣。既然是Java中所定義好的以Stack命名的結構,那就應該是Java設計者們所設計的最合適、最好用的結構了。

然而並不是這樣。
甚至你去查看JDK的官方文檔,都能發現這麼一段話:

“Deque接口及其實現提供了更完整和一致的LIFO堆棧操作集,這些接口應優先於此類”

在這裏插入圖片描述
令人驚訝,Java官方竟然推薦使用隊列(Deque)來實現棧!這一切的原因都在文檔中的另一句話:“從以下版本開始:JDK1.0”

爲什麼不應該使用Stack類?

Stack類繼承自Vector類。Vector是一個動態數組,因而Vector可以在數組中操作任意一個位置的元素。
而因爲Stack繼承自Vector,所以Vector的所有公有方法Stack都可以使用——這就意味着,Stack也可以在任意位置添加或刪除元素!

	Stack<Integer> stack = new Stack<>();
	stack.push(1);
	stack.push(2);
	stack.add(1,3);
	System.out.println(stack);

[1, 3, 2]

上面的代碼是可以運行的。一個設計爲後入先出的結構,竟然可以在其他位置插入元素?你無法想象其他人在使用棧時會不會有意或無意地做出這些操作——一旦做出,代碼的安全性蕩然無存。

Java的設計者在設計Stack時犯了如此荒唐的錯誤。如果Stack和Vector的關係不是繼承而是組合(Stack裏應該擁有一個動態數組,而不是繼承自一個數組!),那麼今天我們就不會在這裏討論這個糟糕的問題。

現在,爲了保證Java代碼的兼容性,這段糟糕的設計仍然保留在JDK中。但是我們應該瞭解Stack的缺陷,並在自己的代碼中避免它。

用什麼結構來替代Stack類?

1. Deque

用一個ArrayDeque可以實現和Stack相同的功能,這也是Java官方所推薦的做法。

	Deque<Integer> stack = new ArrayDeque<>();
	stack.push(1);
	stack.push(2);
	stack.push(3);
	while (!stack.isEmpty())
		System.out.println(stack.pop());

3
2
1

2. LinkedList

沒錯,用LinkedList也可以實現同樣的功能。只不過,LinkedList的接口不那麼直接,或許需要你編寫一個自己的Stack類來包裝一下。

import java.util.LinkedList;

public class Stack<T> {
    LinkedList<T> list;
    public Stack(){
        list = new LinkedList<>();
    }
    
    public void push(T t){
        list.addFirst(t);
    }
    
    public <T> T pop(){
        return (T) list.removeFirst();
    }
    
    public <T> T peek(){
        return (T) list.getFirst();
    }
    
    public boolean empty(){
        return list.isEmpty();
    }
}

用泛型可以很容易地寫出通用的數據結構。而且,通過LinkedList,可以自定義不同的棧,比如雙向棧。你可以自己實現一下。

結語

不要使用java.util.Stack!這是本篇文章的核心論點。使用Stack可能會導致你被面試官掛掉,從今天起培養用Deque代替Stack的習慣。

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