我在以下示例中遇到了一些问题(更准确地说,有一个特定的行)。这是代码(之后的问题):
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
是Down
的一个实例,它继承自Middle
。
我遇到的问题最多的是pp.cc(dd);
和dd.cc(dd)
。
关于在编译时或在运行时确定这些事情的时间和方式,我真的有点困惑。
如果有人能帮我理解,我会很高兴。
答案 0 :(得分:5)
基本上,方法 signature 是在编译时根据所涉及的表达式的编译时类型选择的,并且实现是在执行时选择的,基于该方法的目标的实际实现。
因此,在编译时,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。
答案 1 :(得分:0)
在pp.cc(dd);
中,编译器必须在属于pp类型的方法Up
之间进行选择。最合适的是cc(Middle m)
。您没有在Middle
中覆盖此方法,因此调用运行时Up
方法。
在dd.cc(dd)
中,编译器在属于Down
,Middle
或Up
的方法之间选择,因为dd
是Down
。 Middle
的方法cc(Down)
与dd
的类型完全匹配并被选中。
因此,编译时根据声明的变量类型和最合适的方法签名进行选择。然后,正常覆盖规则应用运行时。