父类构造函数调用子类重写函数

先看下面这段代码,运行后会输出什么结果呢?

public class Polymorphic {
    static class Father{
        public int money = 1;

        public Father(){
            money = 2;
            show();
        }

        public void show() {
            System.out.println("father: $" + money);
        }
    }

    static class Son extends Father{
        public int money = 3;

        public Son() {
            money = 4;
            show();
        }
        
        public void show() {
            System.out.println("son: $" + money);
        }
    }

    public static void main(String[] args) {
        Father gay = new Son();
        System.out.println("gay: $" + gay.money);
    }
}

输出的结果为

son: $0
son: $4
gay: $2

两次都输出的是“son”,这是因为Son类在创建时会先调用父类的构造函数,父类构造函数中调用show(),实际执行的是子类重写的方法,子类show()方法中访问子类的money字段,这是money字段还未被初始化,值为0,字段不参与多态,最后gay访问的是父类的money。

从字节码的角度来看,父类构造函数中调用show()是一次虚方法调用,在Java中静态方法(invokestatic)、私有方法(invokespecial)、实例构造器(invokespecial)、父类方法(invokespecial)以及被final修饰的方法(invokevirtual),这5种方法统称为“非虚方法”,其他方法就称为“虚方法”,使用invokestatic和invokespecial指令调用的方法,在解析阶段就可确定唯一的调用版本,使用invokevirtual指令调用的方法,是在运行期确定方法接收者的实际类型,根据实际类型确定方法执行版本。

在这里插入图片描述

PS: final方法虽然是使用invokevirtual指令调用,但因为它无法被覆盖,没有其他版本的可能,所以不需要对方法接收者进行多态选择。

将Son类改成如下代码:

static class Son extends Father{
        public int money = 3;

        public Son() {
            money = 4;
            super.show();
            show();
        }

        public void show() {
            System.out.println("son: $" + money);
        }
    }

可看到字节码如下:
在这里插入图片描述
在子类中调用父类的show方法是用invokespecial指令调用,调用自身的普通方法是用invokevirtual指令调用。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值