一件事是您用来访问对象的引用,另一件事是对象的实际类型。这是基本的亚型多态性。
您的对象属于 B 类型,因为那是您创建的(即 new B())。现在,您碰巧通过类型 A 的引用访问您的对象,这是可能的,因为 B是A(B 扩展 A)。
当您通过引用调用方法print时,运行时类型系统知道即使引用是 A 类型,引用指向的实际对象也是 B 类型,因此它首先在 B 中查找方法print。那就是当时被调用的那个,它解释了你看到的输出。
您的print方法就是他们所说的虚拟方法。这意味着运行时系统仅根据运行时调用的目标对象的性质来确定将调用方法的所有实现的哪个实现。
现在,清楚地知道,您在 B 中的覆盖实现就是被调用的内容。被覆盖的实现不会自动触发父类中的实现。这与构造函数中的行为有些不同(不能被继承但可以被链接)。
所以,这基本上意味着,如果你想从你的重写方法访问父级的行为,你必须让你的超类去做(即 super.print())
因此,如果您正在处理构造函数,例如以下情况
class A {
public A() { System.out.println("A"); }
}
class B extends A{
public B() { System.out.println("B"); }
}
如果您创建 B 的实例,您应该看到 A B 的输出。因为构造函数是自动链接的,并且 B 中的构造函数调用 A 中的构造函数。
但在虚拟方法的情况下,您需要显式链接执行(如果这是您想要的),如下所示:
class A {
public A() { System.out.println("A"); }
//virtual method
public void print(){ System.out.println("A"); }
}
class B extends {
public B() { System.out.println("B"); }
//virtual method overriden
@Override
public void print(){
super.print(); //invokes A.print
System.out.println("B");
}
}
...为了查看输出 A B。