子类型中的“覆盖”实例变量:可能存在风险?

时间:2010-05-19 10:23:23

标签: java inheritance subclass type-safety

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

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

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

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

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

4 个答案:

答案 0 :(得分:8)

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

  

我可以在someList.size()

中获得Superclass

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

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

答案 1 :(得分:1)

这是一个非常糟糕的主意。你真的想要一个子类的实例拥有两个列表吗?因为那就是发生了什么。你要声明第二个变量 - 所以超类中的代码将使用一个变量,子类中的代码将使用另一个变量。这只是在寻找麻烦,IMO。

答案 2 :(得分:1)

似乎打破IS-A和Liskov替代原则给我。如果你有一个SuperClass实例的集合,每个实例都可以是SubClassA或SubClassB,那么你最多会得到一些令人惊讶的行为。

不要这样做。

使用泛型的东西可能更好:

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

答案 3 :(得分:1)

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

用方法i建议替换变量。

感谢。