2

我有一个关于这个程序如何选择方法的问题。

代码(除了构造函数):

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。就我个人而言,我理解如果有 2 个方法同名,如果有重载,则选择使用静态类型,如果覆盖则使用动态类型;

f1.m(s1)动态搜索Father.m(Son)方法,但它不存在,而是Father.m(Father)被选择

f2.m(s1)动态搜索一个Son.m(Son)存在并且是重载的方法,所以我认为它现在应该优先考虑静态类型并搜索一个Father.m(Son)不存在但最接近的方法是Father.m(Father). 取而代之的Son.m(Father)是选择方法:是被 Son.m(Son) 方法重载的方法,可以,但不是从静态搜索中出来的,那为什么选择它呢?

4

3 回答 3

2

f2 被声明为父亲,然后由儿子实例化。事情是在父亲类中,唯一的 m 方法是接受父亲作为输入参数的方法。因此,当您通过 Son 类实例化 f2 时,只有 theint m(Father f)可用于覆盖。(只要关注 f2,就没有int m(Son f)方法)这就是 f2.m(s1) 返回 100 的原因。

于 2019-10-23T10:17:07.313 回答
2

f2是类型的引用Father。即使它引用的对象是 a ,编译器仍然只允许使用在访问该类型的引用时Son存在的任何方法。Father因此没有其他选择,只能使用带有签名的方法int m(Father)(因为它是唯一存在的方法Father)。由于Son此方法有一个覆盖,因此该覆盖被执行。

f2.m(s1) 动态搜索 Son.m(Son) 方法

这就是你的错误根源所在。它不是在寻找Son.m(Son)方法,而是在寻找Father.m(Son)方法并找到Father.m(Father)方法。稍后会调用覆盖。

于 2019-10-23T10:30:03.407 回答
1

让我们一一分析。

f2 = new Son(3,10);

根据概念 Son 对象将在运行时被绑定。

然后你打电话

f2.m(s1)

现在当它在 Son 对象中搜索 m 方法时。发现有两个 1. m(Father f) 和 2. m(Son s)。

但是引用 f2 是父亲类型,只有 m(Father f) 在 Son 和 Father 对象之间是通用的,因此 Son 对象的 m(Father f) 将在运行时被选择执行(简而言之 m(Son s) 将不可见以父亲为参考)。这就是为什么你会看到这个结果。

您也可以调试代码。它将向您展示相同的执行流程。

于 2019-10-23T10:42:52.163 回答