当前位置: 代码迷 >> J2SE >> 解惑:为什么在父类中调用的是子类的方法?解决思路
  详细解决方案

解惑:为什么在父类中调用的是子类的方法?解决思路

热度:312   发布时间:2016-04-24 01:27:05.0
解惑:为什么在父类中调用的是子类的方法?
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()被重写了
------解决方案--------------------
实例是啥调的就是啥
  相关解决方案