不清楚动态绑定

时间:2019-03-30 17:54:25

标签: java

我不了解动态绑定和适当覆盖的概念:

以下是一些代码:

class Cake {
    public void taste (Cake c) {
        System.out.println("In taste of Cake class");
    }
}

class ChocolateCake extends Cake {
    public void taste(Cake c) {
        System.out.println("In taste (Cake version) of ChocolateCake class");
    }
    public void taste(ChocolateCake cc) {
        System.out.println("In taste (ChocolateCake version) of ChocolateCake class");
    }
}


public static void main(String[] args)
{
    ChocolateCake cc = new ChocolateCake();
    Cake c = new ChocolateCake();
    Cake c1 = new Cake();
    Cake c2 = new ChocolateCake();

    c1.taste(cc);
    c1.taste(c);

    c2.taste(cc);
    c2.taste(c);
}

我期望:

In taste of Cake class
In taste of Cake class
In taste (ChocolateCake version) of ChocolateCake class" <----
In taste (Cake version) of ChocolateCake class

实际:

In taste of Cake class
In taste of Cake class
In taste (Cake version) of ChocolateCake class <----
In taste (Cake version) of ChocolateCake class

如果对象的类型为ChocolateCake,并且我将cc也称为ChocolateCake,那么编译器如何显示它以Cake作为参数?

3 个答案:

答案 0 :(得分:9)

这是因为Java在这种情况下同时使用了静态和动态绑定来选择要调用的方法。

有问题的一行是这个,对吧?

c2.taste(cc);

编译器首先选择要调用的方法(静态绑定)。由于c2的编译时类型为Cake,因此编译器仅看到taste(Cake)方法。因此它说“呼叫taste(Cake)”。

现在,在运行时,运行时需要根据taste(Cake)的运行时类型来选择要调用的c2的实现。这是动态绑定。是否选择Cake中的一个?还是ChocolateCake中的一个?由于c2的运行时类型为ChocolateCake,因此它将在taste(Cake)中调用ChocolateCake的实现。

如您所见,您甚至没有提到您以为将被称为taste(ChocolateCake)的方法!这是因为这是taste方法的不同重载,并且因为它在ChocolateCake类中,编译器无法看到。编译器为什么看不到?因为c2的编译时间类型为Cake

简而言之,编译器决定哪个重载,运行时决定哪个实现。

回应您的声明:

  

如果对象的类型为ChocolateCake ...

只有知道对象的类型为ChocolateCake。编译器没有。它只知道c2的类型为Cake,因为它的声明就是这样。

答案 1 :(得分:8)

由于c2变量的引用类型为Cake,因此将调用具有taste类型参数的Cake方法。

这是因为Cake类型没有采用taste实例的ChocolateCake方法,所以您不能从Cake类型引用中调用该方法变量。

现在,在Java中,由于运行时多态性的机制,正在调用taste的重写ChocolateCake方法,而不是在父Cake类中声明的版本。这是由于实际上在运行时将检查Cake引用所指向的对象,并将调用该特定实例的taste版本。

因此,由于这两种效果的结合,您将看到该输出。

如果将c2的引用类型更改为ChocolateCake,您将看到输出为:

In taste (ChocolateCake version) of ChocolateCake class 

在调用c2.taste(cc);时,由于现在编译器和运行时都同意特别调用该taste(ChocolateCake cc)方法。

答案 2 :(得分:0)

在Java中,根据c2.taste(cc)的编译时类型,在编译时执行c2情况下调用哪种方法集的决定。 c2的编译时类型为Cake,这意味着对c2 any 方法调用仅搜索类Cake及其超类,并且不会搜索Cake(即ChocolateCake)的任何子类,即使所有子类对编译器都是可见的。

基于接收器和参数的实际运行时类型在运行时执行完全动态方法解析的语言很少会导致c2.taste(cc)解析为ChocolateCake.taste(ChocolateCake cc),因为它会对运行时性能产生负面影响。