214

我的用例需要一个Stack数据结构。我应该能够将项目推送到数据结构中,并且我只想从堆栈中检索最后一项。堆栈的JavaDoc说:

Deque 接口及其实现提供了一组更完整和一致的 LIFO 堆栈操作,应优先使用此类。例如:

Deque<Integer> stack = new ArrayDeque<>();

我绝对不想在这里同步行为,因为我将在方法本地使用这个数据结构。除此之外,为什么我更喜欢Deque这里Stack

PS:来自 Deque 的 javadoc 说:

双端队列也可以用作 LIFO(后进先出)堆栈。应优先使用此接口而不是旧的 Stack 类。

4

6 回答 6

252

一方面,它在继承方面更明智。Stack在我看来, extends的事实Vector真的很奇怪。在 Java 早期,IMO 过度使用了继承——Properties这是另一个例子。

对我来说,您引用的文档中的关键词是一致的。Deque公开了一组操作,这些操作都是关于能够从集合的开头或结尾获取/添加/删除项目、迭代等 - 就是这样。故意无法按位置访问元素,Stack因为它Vector.

哦,而且也Stack没有接口,所以如果你知道你需要Stack操作,你最终会提交到一个特定的具体类,这通常不是一个好主意。

也正如评论中指出的那样,Stack并且Deque具有反向迭代顺序:

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


Deque<Integer> deque = new ArrayDeque<>();
deque.push(1);
deque.push(2);
deque.push(3);
System.out.println(new ArrayList<>(deque)); // prints 3, 2, 1

这也在Deque.iterator()的 JavaDocs 中进行了解释:

以正确的顺序返回此双端队列中元素的迭代器。元素将按从第一个(头)到最后一个(尾)的顺序返回。

于 2012-09-21T05:49:35.020 回答
24

以下是 Deque 优于 Stack 的几个原因:

面向对象设计——继承、抽象、类和接口:Stack是一个类,Deque是一个接口。只能扩展一个类,而 Java 中的单个类可以实现任意数量的接口(类型的多重继承)。使用 Deque 接口消除了对具体 Stack 类及其祖先的依赖,并为您提供了更大的灵活性,例如,可以自由扩展不同的类或交换 Deque 的不同实现(如 LinkedList、ArrayDeque)。

不一致:Stack 扩展了 Vector 类,它允许您按索引访问元素。这与堆栈实际应该做的事情不一致,这就是为什么首选 Deque 接口(它不允许这样的操作)——它允许的操作与 FIFO 或 LIFO 数据结构应该允许的操作一致。

性能:Stack 扩展的 Vector 类基本上是 ArrayList 的“线程安全”版本。同步可能会对您的应用程序造成重大的性能影响。此外,使用不需要的功能扩展其他类(如 #2 中所述)会使您的对象膨胀,可能会花费大量额外的内存和性能开销。

于 2020-04-22T05:11:54.087 回答
12

Deque使用over的另一个原因StackDeque能够使用流转换为列表,同时保持 LIFO 概念的应用,而 Stack 没有。

Stack<Integer> stack = new Stack<>();
Deque<Integer> deque = new ArrayDeque<>();

stack.push(1);//1 is the top
deque.push(1)//1 is the top
stack.push(2);//2 is the top
deque.push(2);//2 is the top

List<Integer> list1 = stack.stream().collect(Collectors.toList());//[1,2]

List<Integer> list2 = deque.stream().collect(Collectors.toList());//[2,1]
于 2019-02-05T14:28:29.543 回答
5

这是我对 Stack 类描述中提到的不一致的解释。

如果您在此处查看通用实现- 您会看到集合、映射和列表的实现方法一致。

  • 对于 set 和 map,我们有 2 个带有哈希映射和树的标准实现。第一个是最常用的,第二个在我们需要有序结构时使用(它也实现了自己的接口 - SortedSet 或 SortedMap)。

  • 我们可以使用首选的声明方式,如Set<String> set = new HashSet<String>();查看原因here

但是 Stack 类: 1) 没有自己的接口;2) 是 Vector 类的子类 - 基于可调整大小的数组;那么栈的链表实现在哪里呢?

在 Deque 接口中,我们没有这样的问题,包括两个实现(可调整大小的数组 - ArrayDeque;链表 - LinkedList)。

于 2014-04-14T14:11:30.053 回答
-1

对我来说,缺少这一点:堆栈是线程安全的,因为它是从 Vector 派生的,而大多数双端队列实现不是,因此如果只在单个线程中使用它会更快。

于 2018-12-04T15:10:42.230 回答
-1

性能可能是一个原因。我使用的算法只需用 Deque 替换 Stack,从 7.6 分钟缩短到 1.5 分钟。

于 2019-06-04T09:22:06.497 回答