【发布时间】:2017-10-20 05:53:56
【问题描述】:
我有点了解静态绑定发生在编译时而动态绑定发生在运行时的原理。我已经阅读了几个相关的问题。我可以跟随他们中的许多人的思路,但是当涉及到如下具体问题时,我又搞砸了,失去了逻辑:
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");
}
}
class BirthdayCake extends ChocolateCake {
public void taste(Cake c) {
System.out.println("In taste (Cake version) of BirthdayCake class");
}
public void taste (ChocolateCake cc) {
System.out.println("In taste (ChocolateCake version) of BirthdayCake class");
}
public void taste(BirthdayCake bc) {
System.out.println("In taste (BirthdayCake version) of BirthdayCake class");
}
}
已创建以下对象:
Cake c1 = new Cake();
ChocolateCake cc = new ChocolateCake();
Cake c2 = new ChocolateCake();
Cake c3 = new BirthdayCake();
输出如下:
c1.taste(cc);//Output: In taste of Cake class
cc.taste(cc);//Output: In taste (ChocolateCake version) of ChocolateCake class
c2.taste(cc);//Output: In taste (Cake version) of ChocolateCake class
((BirthdayCake) c3).taste(cc);//Output: In taste (ChocolateCake version) of BirthdayCake class
((BirthdayCake) c3).taste((BirthdayCake) c3);//Output: In taste (BirthdayCake version) of BirthdayCake class
基本上,我的问题是为什么c2.taste(cc) 在ChocolateCake 类中调用taste(Cake c)method?
这是我的想法:
c2 的静态类型是 Cake,它决定了 Cake 中的一个方法将被调用。在运行时,c2的动态类型,即ChocolateCake,决定了ChocolateCake cake中的一个方法会被调用。因为它的参数类型是ChocolateCake,所以最终会调用taste(ChocolateCake cc)。
显然,这种想法是错误的。如果我假设该方法的签名在编译时确定为c2 的静态类型是Cake 并且在类Cake 中只有一个方法。当涉及到运行时,它会调用类ChocolateCake 中的覆盖方法。整个事情是有道理的。我的困惑是为什么它以这种方式工作而不是以前的方式?
我不明白的另一件事是我们不允许编写如下语句,因为它会出现编译错误:
ChocolateCake cc = new Cake();。
但是为什么 ChocolateCake 类型引用最终可能会传递一个 Cake 对象,因为它应该调用 ChocolateCake 类中的 taste(Cake c) 方法来获得上述正确的输出。
我想我还是不明白在对象引用上调用方法的整个过程。就像在编译时决定最佳匹配方法时发生的事情以及之后发生的事情一样,比如说,运行时(我不确定这个过程中是否还有其他阶段)。
谁能帮助说明这个过程? 非常感谢!
【问题讨论】:
-
问题在于参数绑定不是动态的。该参数在运行时仍将是
Cake,因为它在编译时绑定到Cake.cake(Cake c),但方法调用(是动态的)最终将是ChocolateCake.cake(Cake c)。这个问题可能有一个很好的副本,让我们看看我能不能找到一个。 -
谢谢,您的回答几乎解决了我的问题。但是我仍然对我在最后几部分中提到的参数传递感到困惑。也就是说,为什么
ChocolateCake类型引用最终可以传递一个Cake对象,而像ChocolateCake cc = new Cake();这样的语句甚至是不允许的? -
这只是基本的继承。所有蛋糕都是
Cakes,但Cake不是ChocolateCake(可能是,但这不是确定的)。你不会写Woman w = new Human();,因为那也不一定是真的。
标签: java object inheritance reference dynamic-binding