Java 语言中的 Stack 类,有什么问题?

当新建一个栈时,不推荐写成:

Stack<Integer> stack=new Stack<>()

而是:

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

就来说说Java 语言中的 Stack 类,有什么问题?

Java中的Stack类继承了Vector这个类。Vector是一个动态数组

这样Stack就继承了Vector的所有公有方法

Vector作为动态数组,有能力在数组中的任何位置添加或删除元素,Stack也有了这样的能力

stack.add(1,666);

对于栈来说,指定在index为1这个位置插入666这个元素,破坏了栈这种数据结构的封装

用户可能会有意无意地调用这些操作,这就将成为bug的来源

 

出现这样的问题,原因是:

Stack和Vector之间的关系不应该是继承关系,而应该是组合关系(composition)

继承:is-a 是一个,例如:猫是一个动物,猫类继承了动物类

组合:has-a 有一个,例如:车里有一台发动机,发动机类和车类是组合关系(车中有发动机类的对象这个成员变量)

在真实世界中,真正的继承关系很少,组合关系更常用多用组合,少用继承

 

Java官方不改Stack类的原因:

若修改,使用老版本Java的程序将在新的Java环境下无法执行

Deque接口:

Deque其实是双端队列的意思,可以在两端进行插入和删除操作,然后真正的栈只能在同一端做插入和删除操作。

就如前面所说,Stack类的问题是继承了Vector这个类的若干不需要的方法,破坏了封装性。而Deque接口的stack依然有不需要的方法,这是Java的历史遗留问题,现在已经无解了。

总结:虽然 Java 官方推荐使用 Deque 接口实现 stack,但是这样的 stack 也破坏了封装性,并不安全

LinkedList与ArrayDeque的区别:

使用ArrayDeque动态数组,如果触发了扩容操作,世界复杂度为O(n)

使用LinkedList链表,不会牵扯到扩容问题,因此每一个添加操作,时间复杂夫欧式O(1)

可实际上,当数据量达到一定程度的时候,链表的性能是远低于动态数组的,因为链表每添加一个元素都要重新创建一个Node类对象,也就是进行一次new的内存操作,而对内存的操作是非常慢的

总结:在实践中,尤其是面对大规模数据的时候,不应该使用链表

对于ArrayList,如果你的应用场景不需要线程安全的特性,那么对于动态数组,应该使用 ArrayList

 

Stack与ArrayDeque方法的不同:

Stack:

stack.push()

stack.pop()

stack.peek()

ArrayDeque:

stack.addLast()

stack.removeLast()

stack.peekLast()

 

猜你喜欢

转载自blog.csdn.net/di_ko/article/details/115004162
今日推荐