以下示例给我带来了一些问题(更确切地说,是一行).这是代码(后面是问题):
public class Up
{
public void cc(Up u) {System.out.println("A");}
public void cc(Middle m) {System.out.println("B");}
}
public class Middle extends Up
{
public void cc(Up u) {System.out.println("C");}
public void cc(Down d) {System.out.println("D");}
}
public class Down extends Middle
{
public void cc(Up u) {System.out.println("E");}
public void cc(Middle m) {System.out.println("F");}
}
public class Test
{
public static void main(String... args)
{
Up uu = new Up();
Up pp = new Middle();
Down dd = new Down();
uu.cc(pp); // "A"
uu.cc(dd); // "B"
pp.cc(pp); // "C"
pp.cc(dd); // "B"
dd.cc(pp); // "E"
dd.cc(dd); // "D"
}
}
现在uu.cc(pp);和uu.cc(dd);很明显,因为uu是Up的实例,而pp在编译时看起来也像Up. dd最适合的方法是cc(Middle m),因为dd是从Middle继承的Down的一个实例.
我遇到最多问题的行是pp.cc(dd);和dd.cc(dd).
对于在编译时或在运行时确定这些事情的时间以及如何确定这些方法,我确实有点困惑.
如果有人可以帮助我理解我会很高兴.
解决方法:
基本上,方法签名是在编译时根据所涉及表达式的编译时类型选择的,而实现是在执行时根据方法目标的实际实现选择的.
因此,在编译时,pp.cc(dd)会尝试查找Up.cc(Down)的匹配项.最具体的匹配项是Up.cc(Middle),因此这就是编译后的代码中的内容.现在在执行时,该实现将是Up.cc(Middle),因为Middle不会覆盖该方法签名.因此,它打印“ B”.
现在在编译时,dd.cc(dd)尝试查找Down.cc(Down)的匹配项.这里有两个相关的选择-完全匹配参数的Middle.cc(Down)或完全匹配目标类型的Down.cc(Middle).编译器更喜欢Middle.cc(Down).在执行时,该方法在Down中没有再次被覆盖,因此它显示“ D”.
过载分辨率规范的相关位是15.12,尤其是15.12.2 – determining the method signature.