鉴于以下代码块我想了解为什么以及如何强调如何,调用Subclass中的方法print:
class Super {
Super() {
// what happens so that Sub's method print() is invoked
print();
}
public void print() {
System.out.println("in super");
}
}
class Sub extends Super {
Sub() {
super();
}
public void print() {
System.out.println("in sub");
}
}
public class TestClass {
public static void main(String[] args) {
Super s = new Sub(); // "in sub".. not so much expected
s.print(); // "in sub".. as expected
}
}
我的理解是,在编译期间,类将获得与属于某个类的方法相关联的V表指针vtblPtr
。
因此,类Super
应该引用它自己的方法print()
的实现。
为什么在print()
的构造函数中调用Sub
中的方法Super
?这里到底发生了什么?
答案 0 :(得分:3)
以下是JVM的Super
类(实际上,这是javap -c Super
获得的人类可读版本)
class Super {
Super();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: invokevirtual #2 // Method print:()V
8: return
public void print();
Code:
0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String in super
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
如您所见,print
内部Super
构造函数在编译时未解析为Super::print
。虚拟调用意味着它在运行时针对this
类进行解析。
答案 1 :(得分:2)
我的理解是,在编译期间,类将获得V-table pointervtblPtrassociated与方法'属于'类。因此,Class Super应该参考它自己的方法print()的实现。
您对虚拟方法和覆盖有一个基本的误解。在Java中,每个非static
,非 - private
方法都是虚拟的。从任何地方对虚拟方法进行的每次虚拟(正常)调用都将调用与调用该方法的对象的类关联的版本。该版本可能会或可能不会被继承,并且可能会或可能不会覆盖超类的方法。
虚拟方法调用在this
上隐式或显式执行,绝不会改变任何方式。特别是,正在初始化的对象的实际类对于每个构造函数都是可见的,并为其所有方法调用提供上下文。实际上,这就是构造函数调用由自己的类提供的虚方法的好主意。超类构造函数在子类构造函数之前运行,因此如果超类构造函数调用碰巧被子类覆盖的方法,那么该方法将在对象以该方法可能采用的方式完全初始化之前运行。