java - 关于继承的小问题

查看:116
本文介绍了java - 关于继承的小问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

刚从大学进入工作岗位的实习生,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();            
    }
}

//显示效果是
fly
fly
attack

第一个fly是执行了Bee类里的move方法,super.attack();执行后会走到父类里的attack里
再继续为什么走Bee的move()而不是父类的move()

why not?
fly
move
attack

解决方案

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要这么设计虚方法表的调用逻辑,与多态的实现又有什么关系?

有关 jvm 内存机制的具体知识,可见传送门:
《深入理解java虚拟机》学习笔记系列——java内存区域划分
《深入理解java虚拟机》学习笔记系列——对象的内存布局
《深入理解java虚拟机》学习笔记系列——垃圾收集器&内存分配策略

这篇关于java - 关于继承的小问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆