使用超类类型作为子类实例

9 java polymorphism inheritance casting type-conversion

我知道这个问题已被问到很多,但在我看来,通常的答案远非令人满意.

给定以下类层次结构:

class SuperClass{}
class SubClass extends SuperClass{}
Run Code Online (Sandbox Code Playgroud)

为什么人们使用这种模式来实例化SubClass:

SuperClass instance = new SubClass();
Run Code Online (Sandbox Code Playgroud)

而不是这一个:

SubClass instance = new SubClass();
Run Code Online (Sandbox Code Playgroud)

现在,我看到的通常答案是,这是为了instance作为参数发送到需要SuperClass实例的方法,如下所示:

void aFunction(SuperClass param){}

//somewhere else in the code...
...
aFunction(instance);
...
Run Code Online (Sandbox Code Playgroud)

但我可以将一个SubClass实例发送到aFunction,而不管它持有它的变量类型!意味着以下代码将编译并运行而没有错误(假设先前提供的aFunction定义):

SubClass instance = new SubClass();
aFunction(instance);
Run Code Online (Sandbox Code Playgroud)

实际上,AFAIK变量类型在运行时是没有意义的.它们仅由编译器使用!

将变量定义为SuperClass的另一个可能的原因是,如果它有几个不同的子类,并且该变量应该在运行时将它的引用切换为其中的几个,但我举例说,这只发生在类中(不是超级,而不是子类).只是上课).绝对不足以要求一般模式......

chr*_*her 8

这种类型的编码的主要论据是因为Liskov Substituion Principle,它声明if X是类型的子类型T,那么任何实例都T应该能够被替换掉X.

这样做的好处很简单.假设我们有一个包含属性文件的程序,如下所示:

mode="Run"
Run Code Online (Sandbox Code Playgroud)

你的程序看起来像这样:

public void Program
{
    public Mode mode;

    public static void main(String[] args)
    {
        mode = Config.getMode();
        mode.run();
    }
}
Run Code Online (Sandbox Code Playgroud)

简而言之,这个程序将使用配置文件来定义该程序将要启动的模式.在Config类中,getMode()可能如下所示:

public Mode getMode()
{
    String type = getProperty("mode"); // Now equals "Run" in our example.

    switch(type)
    {
       case "Run": return new RunMode();
       case "Halt": return new HaltMode();  
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么这不起作用

现在,因为您有类型的引用,所以Mode只需更改mode属性的值即可完全更改程序的功能.如果有public RunMode mode,您将无法使用此类功能.

为什么这是一件好事

这种模式已经很好地发挥作用,因为它为可扩展性打开了程序.这意味着如果作者希望实现这种功能,那么这种类型的所需功能可以通过最少量的更改实现.我的意思是,来吧.您可以更改配置文件中的一个单词并完全更改程序流,而无需编辑任何一行代码.这是可取的.