public class Question {
public static void main(String[] args) {
MyInterface child = new Child();
//接口多态参数 和 继承 同时出现时的 两种动态绑定现象
//1、正常的动态绑定现象
//child.toSay();
//编译报错:Cannot resolve method 'toSay' in 'MyInterface',可以理解
System.out.println(((Dad) child).toSay());
//输出"toSay Child...",可以理解
child.toString();
//不报错,可以理解
//2、二次动态绑定现象
System.out.println(child.toString());
//输出"toSay Child...",无法理解???
}
}
interface MyInterface {
}
class Grandpa {
public String toSay() {
return "toSay Grandpa...";
}
}
class Dad extends Grandpa implements MyInterface {
public String toString() {
return toSay();
}
public String toSay() {
return "toSay Dad...";
}
}
class Child extends Dad {
public String toSay() {
return "toSay Child...";
}
}
对代码和问题的解释:
1、主方法里最后一句话调用toString,这是第一次动态绑定;
2、toString里面又调用了toSay,这是第二次动态绑定(或者说是方法嵌套调用时,内层方法的动态绑定)。
这两次动态绑定,绑定的东西好像不一样。
第一次(调用toString)是绑定child。
第二次(在toString内部调用toSay)不知道绑定了啥,但肯定不是child了吧。
因为toSay是实现类的私有方法,且child.toSay();会编译报错。
你说的绑定规则我不太理解,但希望以下能帮到你。
1、调用toString方法会先调用Dad的toString方法,然后再调用child的toSay的方法。
2、toSay并不是类的私有方法。child.toSay()方法报错,是因为你接口没有这个方法。他只是引用了Child的一部分功能而已(简单理解)。如果你非想用接口调用toSay(),这么写就会调用成功了。
interface MyInterface {
public String toSay();
}
3、至于为啥toString会有输出“toSay Child...”,是因为你给Dad方法名起成"toString了"。所有类都会集成Object对象的toString()方法。你的Dad刚好重写了他。改个名字,你就会发现它输出的Object对象的toString方法的返回值了。
抱歉,可能我的问题没有表述清楚。
您在第2点中提到——child.toSay()方法报错,是因为你接口没有这个方法。
这一点我理解。
——————————————————————————————————————
另一个回答中@Raiden_xin 提到:
在toString内部调用toSay的时候,还是动态绑定到child。您似乎也是这个意思。
我最初的疑惑是:此时child还是接口类型吗?
如果是接口类型,那child.toSay()就应该报错,但实际上不报错,我猜测原因可能是以下三点之一:
@不可为awen:
1、是接口
2、你这种想法是对的
3、就算Dad中没有toSay也是可以调用到Child的toSay方法。
你的第二种想法更接近答案。toString方法调用toSay方法,其实是这样的 retrun this.toSay()。 这个this就是Child这个类自己。至于为什么是Child,因为你new Child()。在你创建这个对象的时候,这个对象重写了toSting方法的内容。
这么说吧"面向对象"的语言。你说的"如果是接口类型,那child.toSay()就应该报错",这句话看着没问题,但是你搞错了一个概念就是 --> toString()方法里面是this.toSay()还是child.toSay()。
最后总结一下: 在调用toString()时绑定的是接口的toString方法。而toString()方法的内部使用this.toSay(),此方法绑定了Child类本身。
这个很简单啊 两次都绑定的是你的实际类型 也就是 Child
首先你的 父类 覆写了 toString 方法
这个方法是 共有的 也就子类可以继承toString 方法的
所以你调用 toString 这个方法的时候 ,动态绑定的是 Child 即你调用的是Child继承自 Dad 的toString 方法
下面看 toString 方法
public String toString() {
return toSay();
}
toString 中 调用了 toSay 这个调用的时候 也是动态分派的 ,动态绑定到你实际的类型上 即 Child
也就调用的下面这个方法
public String toSay() {
return "toSay Child...";
}
这是一个很典型的动态分派 不明白可以找我
抱歉,可能我的问题没有表述清楚。
——————————————————————————————————————
您提到:
在toString内部调用toSay的时候,还是动态绑定到child。
我最初的疑惑是:此时child还是接口类型吗?
如果是接口类型,那child.toSay()就应该报错,但实际上不报错,我猜测原因可能是以下三点之一:
@不可为awen: 这个东西要去详细说比较复杂,child当然是接口类型,接口是一种抽象,你可以认为是一种身份,这样解释吧,你是你爸爸的儿子,不妨碍你是你老婆的老公,是你儿子的爸爸。都是你,你不能说,你结婚了,有了新的责任,就不是你爸爸的儿子了。对吧。你是接口,但是你实际类型当中有某些方法,当你调用这个方法的时候你还是你,你会这个方法,当然可以调用。这时候连接是在你实际的类型上的。当然如果是父类可以继承的方法。如public的方法,你没有覆写的话,这时候调用的就是你继承来的方法。