public class Test2 {
public static void main(String[] args) {
new RoundGlyph(5);
}
}class Glyph { void draw() {
System.out.println("Glyph draw()");
} Glyph() {
System.out.println("Glyph before draw();");
draw();
System.out.println("Glyph after draw();");
}
}class RoundGlyph extends Glyph {
private int radius = 1; RoundGlyph(int r) {
radius = r;
System.out.println("RoundGlyph(),radius:" + radius);
} void draw() {
System.out.println("RoundGlyph.draw(),radius:" + radius);
}
}
打印结果:Glyph before draw();
RoundGlyph.draw(),radius:0 //这里,为什么调用的是子类的方法呢?
Glyph after draw();
RoundGlyph(),radius:5
谢谢各位了,这边搞不明白.
class Glyph { void draw() { //尝试2,在这个方法前面加上 private
System.out.println("Glyph draw()");
} Glyph() {
System.out.println(this.getClass()); //尝试1,打印对象的类型,看看到底是什么对象
System.out.println("Glyph before draw();");
draw();
System.out.println("Glyph after draw();");
}
}从尝试1可以知道,new RoundGlyph(5);生成的是RoundGlyph对象,如果子类重写了父类的方法,那么调用的就是子类的方法
LZ可以用javap -verbose Glyph 来查看一下Glyph的执行指令,
LZ可以找到如下的指令
invokevirtual #? // Method draw:()V
也就是说,父类在编译的时候,draw方法被编译为一个由virtual-table虚拟表管理的方法(也就是编译为invokevirtual指令),程序执行的时候,会从virtual-table虚拟表中找到实际的方法地址,然后才真正调用方法
子类重写父类方法后,虚拟表里保存的只有子类的方法,所以从虚拟表中找到的是子类的方法从尝试2可以知道,尽管new RoundGlyph(5);生成的是RoundGlyph对象,调用的也是父类的draw方法
LZ可以用javap -verbose Glyph来再次查看编译后的指令,
LZ可以找到如下的指令
invokespecial #? // Method draw:()V
因为private是不可以重写的,所以父类在编译的时候,draw方法将不再编译为virtual-table虚拟表管理的方法(也就是编译为invokespecial指令),所以程序执行的时候,直接从父类中找到方法的地址,然后调用方法,也就是说,程序执行的是父类本身的方法大概就这么个意思了,LZ慢慢领悟吧