2011-02-23 63 views
3

我对以下示例(更确切地说,使用一个特定行)存在一些问题。下面的代码(如下问题之后):Java多态 - 具体示例

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是Uppp的实例“看起来像”一个Up藏汉(在编译时)。对于dd最合适的方法是cc(Middle m),因为dd是从Middle继承的Down的实例。

我遇到的最多问题是pp.cc(dd);dd.cc(dd)。 对于在编译时或运行时确定何时以及如何确定这些方法,我确实有点困惑。 如果有人能帮助我理解,我会很高兴。

回答

5

基本上,该方法签名被选择以基于编译时间类型所涉及的表达式的编译时间,并且实施被选择在执行时,基于实际执行只是目标的的方法。

因此在编译时,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

0

pp.cc(dd);编译器必须在属于pp类型Up的方法之间进行选择。最适合的是cc(Middle m)。您不要在Middle中覆盖此方法,因此运行时将调用Up方法。

dd.cc(dd)的编译器选择在属于DownMiddleUp因为ddDown方法之间。 Middle的方法cc(Down)dd的类型完全匹配并被选中。

因此,编译时选择是基于变量的声明类型和最合适的方法签名。然后正常的覆盖规则应用运行时