为了账号安全,请及时绑定邮箱和手机立即绑定

关于继承的小问题

关于继承的小问题

鸿蒙传说 2019-03-01 10:44:20
刚从大学进入工作岗位的实习生,java方向,进入工作岗位后才知以前学的东西只是知其一不知其二....再从温习继承一块有个疑问 //定义一个昆虫类,里面有攻击和移动两个方法 package test03; public class Insect { private int size; private String color; public int getSize() { return size; } public void setSize(int size) { this.size = size; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public Insect(int size, String color) { this.size = size; this.color = color; } // 移动 public void move() { System.out.println("move"); } // 攻击 public void attack() { // 攻击之前要移动 move(); System.out.println("attack"); } } package test03; //定义一个蜜蜂类,并继承昆虫夫类 public class Bee extends Insect { public Bee(int size, String color) { super(size, color); } @Override public void move() { System.out.println("fly"); } @Override public void attack() { move(); //这里super会调用夫类Insect.attack方法 super.attack(); //System.out.println("Attack"); } } /*测试类*/ public class TestMain { public static void main(String[] args) { Bee b=new Bee(1, "red"); b.attack(); } } //显示效果是flyflyattack 第一个fly是执行了Bee类里的move方法,super.attack();执行后会走到父类里的attack里再继续为什么走Bee的move()而不是父类的move() why not?flymoveattack
查看完整描述

8 回答

?
精慕HU

TA贡献1845条经验 获得超8个赞

1、java类是运行在jvm(java虚拟机)中的,所以这里的执行效果取决于 jvm规范 对于方法执行效果的定义
2、jvm在执行一个方法的时候,有以下知识点

2.1. 执行方法前,虚拟机读取 class文件至内存,并生成对应的 Class 对象放在静态区中。跟你这个问题比较相关的一点是,虚拟机会针对每个类的所有方法,形成一个虚函数表,以实现运行(调用)时的快速查找。

2.2. 当加载一个具有继承体系的类时,会先加载父类,先调用父类的构造函数,在执行子类的构造函数。虚函数表的生成同样也具有这种先后顺序。子类会覆盖同名的父类虚方法表中同名同可见性方法。

2.3. 具有继承层次的类的虚方法表查找,默认先查找子类虚方法表,找不到才会找父类的。

结合题主的例子,当 TestMain 中,执行到b.attack(); 方法时,默认读取的自然是 bee类的虚函数表,由2.2可知:

第一个fly:bee.attack()——> bee.move()
第二个fly:bee.attack()——> bee.move()——> inset.attack()——> bee.move()

//之所以这里会由 insect.attack() 里执行到 bee.move() 就是前面说得,insect 作为实例化 bee 类顺带生成的内置父类对象,默认读取虚方法表会优先从子类开始查找

题外话,题主可以思考一下为什么java要这么设计虚方法表的调用逻辑,与多态的实现又有什么关系?

查看完整回答
反对 回复 2019-03-01
?
jeck猫

TA贡献1909条经验 获得超7个赞

因为Bee类继承了Insect类,所以Bee类调用方法会优先到当前类中找寻,没有才会调用父类的方法,由于Bee类自己存在move方法的,所以就不会调用父类的move方法,而为什么会调用父类的attack方法是因为你用了super,如果你用super.move

查看完整回答
反对 回复 2019-03-01
?
温温酱

TA贡献1752条经验 获得超4个赞

题主可能纠结在于

@Override
public void attack() {        
    move();
    //这里super会调用夫类Insect.attack方法
    super.attack();
    //System.out.println("Attack");
}

都已经执行至父类的attack()方法中了,为什么还会去调用子类的move()方法呢?
对此,不知道该怎么从理论上进行阐述题主的疑惑,只是知道,当前类有的方法就执行,当前类没有或者明确用super关键字指明的,才会执行父类方法

查看完整回答
反对 回复 2019-03-01
?
HUWWW

TA贡献1874条经验 获得超12个赞

因为move方法已经被子类方法重写覆盖了呀
你可能和隐藏字段的概念混淆了
重写方法就是覆盖了,用的只会是子类中的新方法
重写字段只是隐藏了,super调用基类的方法里还是用的基类原来的字段

查看完整回答
反对 回复 2019-03-01
?
函数式编程

TA贡献1807条经验 获得超9个赞

子类重写了父类的 move 方法

查看完整回答
反对 回复 2019-03-01
?
慕桂英3389331

TA贡献2036条经验 获得超8个赞

指令中callcallvirt调用方法的区别,callvirt会优先寻找子类中重写的方法,call则直接调用父类声明的方法。

查看完整回答
反对 回复 2019-03-01
?
慕田峪7331174

TA贡献1828条经验 获得超13个赞

看到题主的这个问题,我想对你说下,在开发行业,基础很重要,基础好才能走更远,否则写代码知其一不知其二,本人现在前端开发一枚,以前搞过安卓、PHP。

查看完整回答
反对 回复 2019-03-01
  • 8 回答
  • 0 关注
  • 456 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号