【问题标题】:Why inheritance works this way in Java?为什么继承在 Java 中以这种方式工作?
【发布时间】:2019-05-26 12:18:54
【问题描述】:

我是 Java 新手,我试图通过模拟以下程序来了解当我将子类实例分配给父类实例变量时会发生什么。

public class ConfusionWithInheritance {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        DerievedClass d = new DerievedClass();
        BaseClass b = BaseClass.class.cast(d);
        BaseClass b1 = new DerievedClass();
        b.doSomeJob();
        b.printMagic(); //-> Compiler shouted me that it didn't know this method here.
    }
}
class BaseClass {
    public void doSomeJob() {
        System.out.println("Printing Value X");
    }
}
class DerievedClass extends BaseClass {
    public void doSomeJob() {
        System.out.println("Printing Value Y");
    }
    public void printMagic() {
        System.out.println("Printing magic...");
    }
}

1) 为什么允许我将子类的实例分配给父类型变量?

2) 从这个answer 可以解释,因为我告诉蓝图类的蓝图是——父类——它只知道父类中的方法。那为什么我在调用 childInstance.doSomeJob() 的时候会在子类的方法中打印值呢?

【问题讨论】:

  • 如果您添加 @Override public void doSomeJob() { 并看到您被允许这样做,第二个答案就会变得清晰。而如果你使用其他方法,你会得到一个编译器错误。
  • 没有充分的理由写SomeClass.class.cast(d):(SomeClass) d 更简洁,并提供更多的编译时检查。
  • Animal a = new Dog();。 Dog 是 Animal。因此,您可以将其分配给这样的变量是有道理的。将变量与实例区分开来。该变量仍然指的是实际的狗。只是变量说“嘿,我可以引用所有动物”。尽管该实例是一条狗并且从技术上讲a.bark() 可以工作,但Java 可以保护您免受这种情况的影响。既然你可以做a = new Cat(),那么它就不再起作用了。可以通过 casting ((Dog) a).bark() 检索类型信息。虽然这通常突出了一个糟糕的设计。

标签: java inheritance single-inheritance


【解决方案1】:

这归结为编译时间和运行时之间存在差异。

在编译时,方法可用是对象被声明的类型中的方法。
在运行时,方法调用是对象被实例化的类型。

因此,对于声明为 BaseClass 类型并实例化为 DerivedClass 类型的对象,可用方法将是 BaseClass 中的方法,即。 doSomeJob(),但方法invoked是DerivedClass中的方法。

【讨论】:

    【解决方案2】:

    创建对象时:

    BaseClass b1 = new DerievedClass();
    

    我们的意思是:

    ReferenceType variableName = new ConcreteImplementation();
    

    将其视为为新对象提供支架的 ReferenceType。

    创建对象时,它会查看此 ReferenceType 并创建一个具有 ReferenceType 中所有方法的对象作为骨架。

    然后我们看一下具体实现方法的实现。 所以编译器会寻找 ConcreteImplementation 来填充所有的方法。

    只有 ReferenceType 中定义的内容才会在最终对象中实现。

    将强制转换视为更改已存在对象的 ReferenceType

    随行:

    DerievedClass d = new DerievedClass();
    

    ReferenceType 是 DerivedClass,所以我们从 DerivedClass 中获取所有方法 并用 DerivedClass 的 ConcreteImplementation 的实现填充它们。

    然后我们将 DerievedClass d 转换为 BaseClass b。

    BaseClass b = BaseClass.class.cast(d);
    

    d 具有 DerivedClass 的所有实现,但脚手架来自 ReferencType BaseClass,因此我们不能调用 printMagic 因为它在 BaseClass 中不存在。

    这有意义吗?

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-01
      • 2013-09-09
      • 2013-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多