Java类Stack从Vector继承了哪些消极方面?
通过扩展类Vector,Java的设计人员能够快速创建类Stack。这种继承用法的负面影响是什么,特别是对于类 Stack?
多谢。
通过扩展类Vector,Java的设计人员能够快速创建类Stack。这种继承用法的负面影响是什么,特别是对于类 Stack?
多谢。
有效的 Java 第 2 版,第 16 项:支持组合而不是继承:
只有在子类确实是超类的子类型的情况下,继承才适用。换句话说,仅当两个类之间存在“is-a”关系时,类 B 才应扩展类 A。如果你想让B类扩展A类,问问自己这个问题:每个B真的是A类吗?如果你不能如实回答这个问题是肯定的,B不应该扩展A。如果答案是否定的,通常情况是B应该包含A的私有实例并公开一个更小,更简单的API;A不是B的重要组成部分,只是其实现的细节。
在 Java 平台库中有许多明显违反此原则的行为。例如,堆栈不是向量,因此不应扩展 。同样,属性列表不是哈希表,因此不应扩展 。在这两种情况下,构图都是可取的。
Stack
Vector
Properties
Hashtable
这本书更详细地介绍了,并结合第17项:设计和继承文档,否则禁止继承,建议不要在设计中过度使用和滥用继承。
下面是一个简单的示例,显示了允许非类似行为的问题:Stack
Stack
Stack<String> stack = new Stack<String>();
stack.push("1");
stack.push("2");
stack.push("3");
stack.insertElementAt("squeeze me in!", 1);
while (!stack.isEmpty()) {
System.out.println(stack.pop());
}
// prints "3", "2", "squeeze me in!", "1"
这是对堆栈抽象数据类型的严重违反。
在计算机科学中,堆栈是后进先出(LIFO)抽象数据类型和数据结构。
一个问题是Stack是一个类,而不是一个接口。这与集合框架的设计不同,在集合框架中,您的名词通常表示为接口(例如,List,Tree,Set等),并且有特定的实现(例如,ArrayList,LinkedList)。如果Java可以避免向后兼容性,那么更合适的设计将是有一个Stack接口,然后VectorStack作为实现。
第二个问题是Stack现在绑定到Vector,这通常被避免,以支持ArrayLists等。
第三个问题是,您无法轻松提供自己的堆栈实现,并且堆栈支持非常非堆栈的操作,例如从特定索引中获取元素,包括潜在的索引异常。作为用户,您可能还必须知道堆栈的顶部是位于索引 0 还是索引 n。该接口还公开了实现详细信息,例如容量。
在原始Java类库中的所有决策中,我认为这是最奇特的决策之一。我怀疑聚合会比继承昂贵得多。