动态方法调度和继承

时间:2013-07-14 06:14:40

标签: java inheritance

我正在阅读一本JAVA书,并遇到了动态方法调度。但这对我来说有点混乱(也许是因为我是个新人)。该书说它基于以下原则:超类引用变量可以引用子类对象。

    class X{
    void display()
    {
       System.out.println("This is class X");
    }
    }

    class Y extends X{
    void display()
    {
        System.out.println("This is class Y");
    }
    void play()
    {
        System.out.println("PLAY!");
    }
    }

    class k{
    public static void main(String args[]){
    X obj1 = new X();
    Y obj2 = new Y();
    X ref  = new X();

    ref = obj1;
    ref.display();
    //output is :This is class X

    ref = obj2;   //Using the principle stated above
    ref.display();
    //output is :This is class Y

    ref.play();  //Compiler error:Play not found 
    //well it must be because ref is of X type and for X no methods of its subclass "Y"
    //is visible
    }
    }

所以我想问一下         玩() 为什么不可见         显示()  Y是可见的吗?

4 个答案:

答案 0 :(得分:1)

根据 promises 来考虑它。 X ref 承诺它拥有的内容(如果有的话)属于X类型。当然,Y也属于X类型,这就是子类化的含义:Y的每个实例都是X的一个实例(加上一些调整和额外的特征)。但是,根据语言定义,无法通过它调用play方法,因为内容不是已知Y

您可以明确地 refY,然后在其上调用play

((Y) ref).play();

这是安全的,因为Java中的每个对象都知道自己的真实类型。如果对象引用是错误类型的实例(例如,obj1),则在运行代码时将获得ClassCastException。 (如果你知道C,这完全不同。)

答案 1 :(得分:0)

父类引用包含从父级继承的子对象的属性。因此,您可以从包含子对象的父引用调用所有这些方法,这些子对象由子类继承并覆盖。

简而言之,引用将决定可以调用哪些方法,它所持有的对象将决定哪个方法(父/子类)将被调用。

  

所以我想问一下,如果play()不可见,那么为什么要显示()   Y是可见的??

显示是可见的,因为这是父参考的方法。但是游戏只属于孩子,因此父母看不到。

答案 2 :(得分:0)

静态类型检查确保您只能调用那些属于引用的静态(声明)类型的方法。这就是为什么你不能通过类型为X的引用调用.play()。

但是,动态方法分派确保,如果在子类中重写方法,则将动态调用该特定方法(在运行时)。

答案 3 :(得分:0)

在执行之前,Java程序由编译器处理。编译器确保在许多其他方面只调用现有方法。在上面的例子中,编译器只知道 ref X 类型,如声明的那样,并且 X 类型没有方法播放。它不会跟踪所有分配,也不会考虑 ref 是由 y 类型的 obj2 分配的 - 这种跟踪通常是不可能的case,因为它可能依赖于运行时数据,在编译时不可用。

另一方面,运行时的方法调用依赖于实际类型,它可以是声明类型的扩展。编译器发出的完全相同的代码可以调用方法 display 的不同实现,具体取决于变量 ref 引用的对象的实际类型。但是,编译器检查可能分配给 ref 的所有可能类型的对象存在方法 display