- Java code
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); }}
打印结果:
- Java code
Glyph before draw(); RoundGlyph.draw(),radius:0 //这里,为什么调用的是子类的方法呢?Glyph after draw(); RoundGlyph(),radius:5
谢谢各位了,这边搞不明白.
------解决方案--------------------
这个应该是多态吧,调用哪个draw方法,跟this的具体类型有关吧
------解决方案--------------------
RoundGlyph子类重写了Glyph父类的draw方法,当继承的时候子类可以假设拥有一个父类的(看不见)引用,当要用到父类的一切方法都会通过这个引用调用,如果子类重写的父类的方法,这个引用就不会指向父类的方法,而是重写后的方法。只要子类重写父类的方法总是调用重写后的。
------解决方案--------------------
这个问题没法一两句跟你说清楚,LZ试着
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慢慢领悟吧
------解决方案--------------------
父类draw()被重写了
------解决方案--------------------
实例是啥调的就是啥