为什么这个静态绑定不能像我预期的那样工作?

Why this static binding doesn't work as i would expect?

我对这个程序如何选择方法有疑问。

代码(除了构造函数):

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)方法重载的方法好吧,但是它不是从静态搜索中出来的,那么为什么选择它呢?

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

f2Father 类型的引用。即使它引用的对象是 Son,编译器仍然只允许在访问该类型的引用时使用存在于 Father 中的任何方法。因此,除了使用带有签名 int m(Father) 的方法(因为它是 Father 中唯一存在的方法)之外别无选择。由于 Son 具有此方法的覆盖,因此将执行该覆盖。

f2.m(s1) searches dynamically for a Son.m(Son) method

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

下面我们一一分析。

f2 = new Son(3,10);

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

然后你打电话给

f2.m(s1)

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

但是引用 f2 是 Father 类型,只有 m(Father f) 在 Son 和 Father 对象之间是公共的,因此 Son 对象的 m(Father f) 将在 运行t 时间被选择执行(在short m(Son s) 不会以 Father 作为参考可见)。这就是您看到该结果的原因。

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