2015-06-30 46 views
16

简单的问题,奇怪的结果。我有两个类AB扩展类的重载方法

public class A 
{ 
    protected int num; 

    public A(int n) 
    { 
     num = n; 
    } 

    public boolean f(A a) 
    { 
     return num == a.num * 2; 
    } 
} 

public class B extends A 
{ 
    public B(int n) 
    { 
     super(n); 
    } 

    public boolean f(B b) 
    { 
     return num == b.num; 
    } 
} 

为什么y1.f(y2)呼叫f()方法A,而不是在B

A y1 = new B(10); 
B y2 = new B(10); 

System.out.println(y1.f(y2)); 

难道不应该叫f()B作为BA更具体?

回答

32

为什么y1.f(y2)在A中而不是在B中调用f()方法?

因为编译时间类型y1A

超载在编译时进行......你调用该方法的对象的执行时类型仅适用于覆盖相关。

所以编译器选择方法f(A),因为它是唯一的f方法,它知道它可以调用y1(并且检查它适用于参数列表)。该方法在B中未被覆盖,因此在执行时调用A中的隐含法。

作为一个有着天壤之别例如,考虑下面的代码:

Object x = "foo"; 
int length = x.length(); 

这甚至不会编译,因为Object不包含length()方法。 String呢,但编译器并没有考虑到这一点,因为x的编译时间类型是Object,而不是String - 尽管我们可以知道在执行时,x的值将引用String对象。

+0

尽管@ JonSkeet的回答总是不容置疑的,只是也支持这个字节代码..你也可以检查什么方法正在通过,你可以看到编译代码为'(y1.f(y2)) '当你看到字节码 '25:invokevirtual#27 // Method com/package1/Af:(Lcom/p ackage1/A;)Z' –