为什么继承在Java中是这样工作的?

为什么继承在Java中是这样工作的?,java,inheritance,single-inheritance,Java,Inheritance,Single Inheritance,我是Java新手,我试图通过模拟下面的程序来理解当我将一个子类实例分配给一个父类实例变量时会发生什么 public class ConfusionWithInheritance { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub DerievedClass d = new DerievedClass();

我是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) 从这里可以看出,因为我告诉类的蓝图是父类,所以它只知道父类中的方法。那么,当我调用childInstance.doSomeJob()时,为什么要在child类的方法中打印值呢?

创建对象时:

BaseClass b1 = new DerievedClass();
我们要说的是:

ReferenceType variableName = new ConcreteImplementation();
将其视为为为新对象提供支架的引用类型

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

然后我们看看具体的实现方法的实现。 因此,编译器期待具体的实现来填充所有的方法

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

将强制转换视为更改已存在对象的引用类型

用这句话:

DerievedClass d = new DerievedClass();
ReferenceType是DerivedClass,因此我们从DerivedClass获取所有方法 并用派生类的具体实现来填充它们

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

BaseClass b = BaseClass.class.cast(d);
d具有来自DerivedClass的所有实现,但脚手架来自ReferenceType基类,因此我们不能调用printMagic 因为它不存在于基类中

这有意义吗


希望它在创建对象时有所帮助:

BaseClass b1 = new DerievedClass();
我们要说的是:

ReferenceType variableName = new ConcreteImplementation();
将其视为为为新对象提供支架的引用类型

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

然后我们看看具体的实现方法的实现。 因此,编译器期待具体的实现来填充所有的方法

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

将强制转换视为更改已存在对象的引用类型

用这句话:

DerievedClass d = new DerievedClass();
ReferenceType是DerivedClass,因此我们从DerivedClass获取所有方法 并用派生类的具体实现来填充它们

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

BaseClass b = BaseClass.class.cast(d);
d具有来自DerivedClass的所有实现,但脚手架来自ReferenceType基类,因此我们不能调用printMagic 因为它不存在于基类中

这有意义吗


希望它能有所帮助

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

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


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

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

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


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

如果添加
@Override public void doSomeJob(),第二个答案将变得清晰{
并查看是否允许您这样做。如果您对另一个方法这样做,您将得到一个编译器错误。没有很好的理由编写
SomeClass.class.cast(d)
(SomeClass)d
更简洁,并提供更多的编译时检查。
Animal a=new Dog()
是一种
动物
。因此,您可以将其分配给这样一个变量。将变量与实例区分开来。该变量仍然引用实际的狗。只是该变量说“嘿,我可以引用所有动物”。尽管该实例是一只狗,从技术上讲是
A.bark()
会起作用,Java会保护您不受此影响。因为您可以执行
a=new Cat()
,然后它就不再起作用了。可以通过强制执行
((Dog)a).bark()来检索类型信息
。虽然这通常会突出显示一个糟糕的设计。可能与此相关:如果添加
@Override public void doSomeJob(){
并查看是否允许这样做,第二个答案就会变得清晰。而如果对另一个方法这样做,则会出现编译器错误。没有充分的理由编写
SomeClass.class.cast(d)
(SomeClass)d
更简洁,并提供更多编译时检查。
Animal a=new Dog()
是一种
动物
。因此,您可以将其分配给这样一个变量。将变量与实例区分开来。该变量仍然引用实际的狗。只是该变量说“嘿,我可以引用所有动物”。尽管该实例是一只狗,从技术上讲是
A.bark()
会起作用,Java会保护您不受此影响。因为您可以执行
a=new Cat()
,然后它就不再起作用了。可以通过强制执行
((Dog)a).bark()
来检索类型信息。尽管这通常会突出显示出一个糟糕的设计。可能与此相关: