Java类Stack从Vector继承了哪些消极方面?

2022-09-02 22:57:11

通过扩展类Vector,Java的设计人员能够快速创建类Stack。这种继承用法的负面影响是什么,特别是对于类 Stack?

多谢。


答案 1

有效的 Java 第 2 版,第 16 项:支持组合而不是继承

只有在子类确实是超类的子类型的情况下,继承才适用。换句话说,仅当两个类之间存在“is-a”关系时,类 B 才应扩展类 A。如果你想让B类扩展A类,问问自己这个问题:每个B真的是A类吗?如果你不能如实回答这个问题是肯定的,B不应该扩展A。如果答案是否定的,通常情况是B应该包含A的私有实例并公开一个更小,更简单的API;A不是B的重要组成部分,只是其实现的细节。

在 Java 平台库中有许多明显违反此原则的行为。例如,堆栈不是向量,因此不应扩展 。同样,属性列表不是哈希表,因此不应扩展 。在这两种情况下,构图都是可取的。StackVectorPropertiesHashtable

这本书更详细地介绍了,并结合第17项:设计和继承文档,否则禁止继承,建议不要在设计中过度使用和滥用继承。

下面是一个简单的示例,显示了允许非类似行为的问题:StackStack

    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"

这是对堆栈抽象数据类型的严重违反。

另请参见


答案 2

一个问题是Stack是一个类,而不是一个接口。这与集合框架的设计不同,在集合框架中,您的名词通常表示为接口(例如,List,Tree,Set等),并且有特定的实现(例如,ArrayList,LinkedList)。如果Java可以避免向后兼容性,那么更合适的设计将是有一个Stack接口,然后VectorStack作为实现。

第二个问题是Stack现在绑定到Vector,这通常被避免,以支持ArrayLists等。

第三个问题是,您无法轻松提供自己的堆栈实现,并且堆栈支持非常非堆栈的操作,例如从特定索引中获取元素,包括潜在的索引异常。作为用户,您可能还必须知道堆栈的顶部是位于索引 0 还是索引 n。该接口还公开了实现详细信息,例如容量。

在原始Java类库中的所有决策中,我认为这是最奇特的决策之一。我怀疑聚合会比继承昂贵得多。


推荐