我知道静态绑定在编译时发生的原则,而动态绑定在运行时发生。我已经阅读了几个相关的问题。我可以按照他们中的许多思路进行思考,但是当我遇到如下具体问题时,我又搞砸了并失去了逻辑:
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)
在课程taste(Cake c)
中调用ChocolateCake
方法?
这是我的想法:
c2
的静态类型为Cake
,它决定要调用Cake
中的方法。当涉及到运行时,动态类型的c2,即ChocolateCake
,决定调用ChocolateCake
cake中的方法。由于其参数的类型为ChocolateCake
,因此最终会调用taste(ChocolateCake cc)
。
c2
的静态类型是Cake
并且类Cake
中只有一个方法。当涉及到运行时,它将调用类ChocolateCake
中的覆盖方法。整个事情都有意义。我的困惑是,它为什么会这样工作而不是以前的方式呢?
我不明白的另一件事是我们不允许写下面的声明,因为它会出现编译错误:
ChocolateCake cc = new Cake();
。
但是为什么ChocolateCake类型引用最终可以传递一个Cake对象,因为它应该调用类taste(Cake c)
中的ChocolateCake
方法来获得正确的输出。
我想我仍然不了解在对象引用上调用方法的整个过程。就像在编译时决定最佳匹配方法以及之后发生的事情一样,让我们说,运行时(我不确定此过程中是否还有其他阶段)。
任何人都可以帮助说明这个过程吗? 非常感谢!
答案 0 :(得分:0)
让我尝试简化示例并完成这些步骤。为了清晰起见,我还添加了@Override。
class Cake {
public void taste (Cake c) {
System.out.println("In taste of Cake class");
}
}
class ChocolateCake extends Cake {
@Override
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");
}
}
ChocolateCake param = new ChocolateCake();
Cake cake = new ChocolateCake();
cake.taste(param);
当你调用cake.taste(param);
时,java编译器会根据引用的类型选择编译时调用哪个方法,而不是引用所指向的实际对象类型。
cake
的引用类型为Cake
,因此编译器会在基类Cake
中查找名为taste
并接受Cake
的方法作为参数。由于ChocolateCake
是Cake
(通过继承),编译器会找到匹配项。
因为基本上你有一个基础taste
方法的覆盖,在运行时和由于动态分派,JVM解析cake
引用的实际类型,即ChocolateType
和调用已经选择的方法的覆盖。
答案 1 :(得分:0)
我已经尝试使用以下main():
public static void main(String[] args)
{
ChocolateCake cc = new ChocolateCake();
Cake c = new ChocolateCake();
Cake c1 = new Cake();
Cake c2 = new ChocolateCake();
Cake c3 = new BirthdayCake();
ChocolateCake c4 = new BirthdayCake();
c1.taste(cc);
c1.taste(c);
c2.taste(cc);
c2.taste(c);
c3.taste(cc);
c3.taste(c);
c4.taste(cc);
c4.taste(c);
}
输出如下:
In taste of Cake class
In taste of Cake class
In taste (Cake version) of ChocolateCake class
In taste (Cake version) of ChocolateCake class
In taste (Cake version) of BirthdayCake class
In taste (Cake version) of BirthdayCake class
In taste (ChocolateCake version) of BirthdayCake class
In taste (Cake version) of BirthdayCake class
到目前为止,我的理解如下:
例如
c4.taste(cc);//c4:ChocolateCake cc:ChocolateCake -> ChocolateCake version
c4.taste(c);//c4:ChocolateCake c:Cake -> Cake version
只是一些自己的理解,对于Java还是很新的;)