首页 新闻 会员 周边

Java的方法嵌套调用,且接口和继承同时出现时,内层方法动态绑定的奇怪现象?

0
悬赏园豆:5 [待解决问题]
 
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. 水平:Java初学者
  2. 动态绑定:某对象向上转型后,只能调用
    2.1. 父类中没被重写的方法
    2.2. 子类中重写了的父类中已有的方法
    2.3. 接口实现类中实现了的上级接口中已有的方法
  • 对代码和问题的解释:
    1、主方法里最后一句话调用toString,这是第一次动态绑定;
    2、toString里面又调用了toSay,这是第二次动态绑定(或者说是方法嵌套调用时,内层方法的动态绑定)。

  • 这两次动态绑定,绑定的东西好像不一样。

  1. 第一次(调用toString)是绑定child。

  2. 第二次(在toString内部调用toSay)不知道绑定了啥,但肯定不是child了吧。
    因为toSay是实现类的私有方法,且child.toSay();会编译报错。

  • 那第二次绑定的是啥呢?或者说第二次的动态绑定规则是啥呢?
不可为awen的主页 不可为awen | 初学一级 | 园豆:194
提问于:2022-04-24 14:21
< >
分享
所有回答(2)
0

你说的绑定规则我不太理解,但希望以下能帮到你。

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方法的返回值了。

mowen285 | 园豆:660 (小虾三级) | 2022-04-26 17:01

抱歉,可能我的问题没有表述清楚。
您在第2点中提到——child.toSay()方法报错,是因为你接口没有这个方法。
这一点我理解。
——————————————————————————————————————
另一个回答中@Raiden_xin 提到:
在toString内部调用toSay的时候,还是动态绑定到child。您似乎也是这个意思。
我最初的疑惑是:此时child还是接口类型吗?
如果是接口类型,那child.toSay()就应该报错,但实际上不报错,我猜测原因可能是以下三点之一:

  1. 此时child不是接口类型
  2. 在toString内部调用toSay的时候,并不是动态绑定到child,而是由其他的方法调用规则
  3. 在这种方法嵌套调用的时候,不用看编译类型,只用看运行类型(以及注意父类不能调用子类的特有方法,因为当Dad中没有toSay的时候,也是无法调用到Child的toSay方法的)
    ——————————————————————————————————————
    以上三点猜测您更倾向于哪一种,或者您的观点是什么?
支持(0) 反对(0) 不可为awen | 园豆:194 (初学一级) | 2022-04-29 22:35

@不可为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类本身。

支持(0) 反对(0) mowen285 | 园豆:660 (小虾三级) | 2022-05-03 14:52
1

这个很简单啊 两次都绑定的是你的实际类型 也就是 Child
首先你的 父类 覆写了 toString 方法
这个方法是 共有的 也就子类可以继承toString 方法的
所以你调用 toString 这个方法的时候 ,动态绑定的是 Child 即你调用的是Child继承自 Dad 的toString 方法
下面看 toString 方法
public String toString() {
return toSay();
}
toString 中 调用了 toSay 这个调用的时候 也是动态分派的 ,动态绑定到你实际的类型上 即 Child
也就调用的下面这个方法
public String toSay() {
return "toSay Child...";
}
这是一个很典型的动态分派 不明白可以找我

Raiden_xin | 园豆:268 (菜鸟二级) | 2022-04-29 21:28

抱歉,可能我的问题没有表述清楚。
——————————————————————————————————————
您提到:
在toString内部调用toSay的时候,还是动态绑定到child。
我最初的疑惑是:此时child还是接口类型吗?
如果是接口类型,那child.toSay()就应该报错,但实际上不报错,我猜测原因可能是以下三点之一:

  1. 此时child不是接口类型
  2. 在toString内部调用toSay的时候,并不是动态绑定到child,而是由其他的方法调用规则
  3. 在这种方法嵌套调用的时候,不用看编译类型,只用看运行类型(以及注意父类不能调用子类的特有方法,因为当Dad中没有toSay的时候,也是无法调用到Child的toSay方法的)
    ——————————————————————————————————————
    个人认为第三点可能更像您说的动态分派。
    以上三点猜测您更倾向于哪一种,或者您的观点是什么?
支持(0) 反对(0) 不可为awen | 园豆:194 (初学一级) | 2022-04-29 22:38

@不可为awen: 这个东西要去详细说比较复杂,child当然是接口类型,接口是一种抽象,你可以认为是一种身份,这样解释吧,你是你爸爸的儿子,不妨碍你是你老婆的老公,是你儿子的爸爸。都是你,你不能说,你结婚了,有了新的责任,就不是你爸爸的儿子了。对吧。你是接口,但是你实际类型当中有某些方法,当你调用这个方法的时候你还是你,你会这个方法,当然可以调用。这时候连接是在你实际的类型上的。当然如果是父类可以继承的方法。如public的方法,你没有覆写的话,这时候调用的就是你继承来的方法。

支持(0) 反对(0) Raiden_xin | 园豆:268 (菜鸟二级) | 2022-04-30 08:34
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册