日期:2014-05-20  浏览次数:20691 次

解惑:为什么在父类中调用的是子类的方法?
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()被重写了
------解决方案--------------------
实例是啥调的就是啥