我对这个程序如何选择方法有疑问。
代码(不包括构造函数):
class Father {
int x;
..
public int m(Father f) {
return (f.x - this.x);
}
}
class Son extends Father {
int y;
...
public int m(Father f) {
return 100;
}
public int m(Son s) {
return super.m(s) + (s.y - this.y);
}
}
主要:
Father f1, f2;
Son s1;
f1 = new Father(3);
f2 = new Son(3,10);
s1 = new Son(4,21);
System.out.println(f1.m(s1) + f2.m(s1));
我不明白为什么f2.m(s1)
会打印100。
我个人理解,如果有两个具有相同名称的方法,如果有重载,则选择使用静态类型,如果覆盖它,则使用动态类型;
f1.m(s1)
动态搜索Father.m(Son)
方法,但该方法不存在,而是选择了Father.m(Father)
f2.m(s1)
动态搜索存在的Son.m(Son)
方法,并且该方法是重载的,因此我认为它现在应该优先处理静态类型,并且搜索Father.m(Son)
方法,该方法不t存在,但最接近的是Father.m(Father)
。
相反,选择了Son.m(Father)
方法:Son.m(Son)方法可以重载该方法,但是它不是从静态搜索中得出的,那么为什么选择它呢?>
答案 0 :(得分:2)
f2被声明为父亲,然后由儿子实例化。事情是在父亲类中唯一的m方法是接受父亲作为输入参数的方法。因此,当您通过Son类实例化f2时,仅int m(Father f)
可用于覆盖。 (只要关注f2,就没有int m(Son f)
方法),这就是f2.m(s1)返回100的原因。
答案 1 :(得分:2)
f2
是类型Father
的引用。尽管其引用的对象是Son
,但是编译器在访问该类型的引用时仍然仅允许使用Father
中存在的任何方法。因此,别无选择,只能使用带有签名int m(Father)
的方法(因为它是Father
中唯一的方法)。由于Son
具有此方法的替代,因此将执行该替代。
f2.m(s1)动态搜索Son.m(Son)方法
这就是您的错误根源。它不是在寻找Son.m(Son)
方法,而是在寻找Father.m(Son)
方法并找到一个Father.m(Father)
方法。调用覆盖会在以后发生。
答案 2 :(得分:1)
让我们一一分析。
f2 = new Son(3,10);
根据概念,Son对象将在运行时绑定。
然后您致电
f2.m(s1)
现在,当它在Son对象中搜索m方法时。发现其中有两个:1. m(父亲f)和2. m(儿子s)。
但是引用f2是父亲类型,并且子对象和父亲对象之间只有m(父亲f)是公共的,因此将在短时间内选择要执行的Son对象的m(父亲f)(简称m(Son s)以父亲为参考不可见)。这就是为什么您看到那个结果。
您也可以调试代码。它将向您显示相同的执行流程。