假设,我们有这两个类和一个主方法:
public class Super {
public void f(double d){
System.out.println("Super: f(double d)");
}
public void f(int i){
System.out.println("Super: f(int i)");
}
}
public class Sub extends Super {
public void f(double d){
System.out.println("Sub: f(double d)");
}
public void f(float f){
System.out.println("Sub: f(float f)");
}
}
public class M {
public static void main(String[] args){
Sub a = new Sub();
a.f(1.5f); //output: "Sub: f(float f)"
Super b = new Sub();
b.f(1.5f); //output: "Sub: f(double d)"
}
}
为什么第二次调用的结果是Sub: f(double d)
而不是像第一次那样Sub: f(float f)
?
当我添加
public void f(float f) {
System.out.println("Super: f(float f)");
}
对于Super
类,输出更改为 Sub: f(float f)
。
鉴于此行为,我希望工作流如下所示:
- 当
a
被向上转换为Super
时,将检查类Super
的匹配方法 - 只找到
public void f(double d)
,所以浮子被铸造成双精度 - 现在,查看并执行了更具体的类
Sub
中public void f(double d)
的方法
这是对的吗?
若要理解此行为,请注意,选择要从一系列重载方法中调用的方法始终在编译时执行。但是,方法调度是在运行时执行的。
因此,在编译时,只有double
版本可见,但它将在运行时调度到子类的重写版本。
编译时查找b.f(1.5f)
的方法。它的实现在运行时将是更具体的实现(如果存在),但在编译时选择哪个重载方法。
由于b
至少是一个Super
编译器可以推断出的唯一结论是该方法将被void f(double v)
(因为Super
没有float
重载),因此选择一个。
然后在运行时,由于动态绑定,实现是类Sub
之一。