【问题标题】:"Overriding" instance variables in subtype: Possible risks?子类型中的“覆盖”实例变量:可能的风险?
【发布时间】:2010-05-19 10:23:23
【问题描述】:

假设我有一个 SuperClass 类和两个从 SuperClass 继承的子类 SubClassA 和 SubClassB。

 abstract class SuperClass{
   ...
   List someList;
   ...
 }

 class SubClassA extends SuperClass{
   ...
   List<String> someList;
   ...
 }

 class SubClassB extends SuperClass{
   ...
   List<Integer> someList;
   ...
 }

这样很方便,因为我可以在Superclass 中获得someList.size() 并在子类中具有类型安全性。 问题是它“感觉”不对,你能想到这个方法有我不知道的潜在危险吗?

【问题讨论】:

    标签: java inheritance subclass type-safety


    【解决方案1】:

    一方面,SuperClass 的任何方法都看到超类列表,而不是子类列表。这几乎肯定会导致微妙的错误。例如。当你说

    我可以在Superclass中得到someList.size()

    您实际得到的是Superclass 中列表的大小,而不是子类的大小。超类列表可能为空,而子类列表包含元素(反之亦然)。

    这背后的原因是SubClassA.someList 不会以任何方式替换或覆盖Superclass.someList - 它只是隐藏它,因此子类方法看到SubClassA.someList 而不是Superclass.someList。但是,这对Superclass 完全没有影响。方法可以是虚拟的(在 Java 中,它们是默认的),但数据成员不能。

    【讨论】:

    • 它们可能是指向同一个对象的不同引用。 (尽管privatefinal 会一如既往地提供帮助。)
    • @Tom,好点子,没有想到这一点......可能是因为,虽然语义上正确,但这仍然是一个丑陋、不必要的复杂、难以理解的解决方案(对我来说)。
    • 我发现很难,它实际上是阴影。我在这里做的唯一一件事就是欺骗编译器(和我)。
    【解决方案2】:

    这是一个非常糟糕的主意。你真的想要任何一个子类的实例都有两个列表吗?因为这就是正在发生的事情。您正在声明第二个变量 - 因此超类中的代码将使用一个变量,而子类中的代码将使用另一个。这只是自找麻烦,IMO。

    【讨论】:

      【解决方案3】:

      我认为你应该定义一个方法而不是类成员变量。这样您就可以在子类中实现方法,而不必担心类型安全。

      用我建议的方法替换变量。

      谢谢。

      【讨论】:

        【解决方案4】:

        对我来说似乎打破了 IS-A 和 Liskov 替换原则。如果您有一组 SuperClass 实例,每个实例都可以是 SubClassA 或 SubClassB,那么您最多会得到一些令人惊讶的行为。

        别这样。

        也许使用泛型会更好:

        public class X<T>
        {
            private List<T> list;
        }
        

        【讨论】:

          猜你喜欢
          • 2014-11-29
          • 1970-01-01
          • 2016-12-26
          • 1970-01-01
          • 1970-01-01
          • 2015-10-07
          • 1970-01-01
          • 2020-01-25
          • 2016-03-03
          相关资源
          最近更新 更多