为什么这个静态绑定不能像我预期的那样工作?
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.
f2
是 Father
类型的引用。即使它引用的对象是 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 作为参考可见)。这就是您看到该结果的原因。
您也可以调试代码。它将向您显示相同的执行流程。
我对这个程序如何选择方法有疑问。
代码(除了构造函数):
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.
f2
是 Father
类型的引用。即使它引用的对象是 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 作为参考可见)。这就是您看到该结果的原因。
您也可以调试代码。它将向您显示相同的执行流程。