为什么此静态绑定无法按我期望的那样工作?

时间:2019-10-23 09:49:15

标签: java overriding overloading dynamic-binding static-binding

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

代码(不包括构造函数):

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

3 个答案:

答案 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)以父亲为参考不可见)。这就是为什么您看到那个结果。

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