Java重写方法调用的本质

标题太大,在这里写一部分,在 JVM 中,方法的调用被广泛称为分派,运行期根据实际类型确定方法执行版本的分派过程称为动态分派,如重写方法的调用。

动态分派的理解:根据对象的实际类型,来确认调用的方法版本,子类有重写方法,则调用子类的重写方法,否则去父类找对应的方法,这就是 invokevirtual 指令的执行逻辑,这是 java 里面对于方法重写的本质。

以下代码中的 Father gay = new Son(); 中,Father 称为变量的静态类型,Son 称为变量的实际类型。

这里贴出一段代码,思考 main 方法的输出是什么,在看结果

public class FieldHasNoPolymorphic {

    static class Father{
        public int money = 1;
        public Father(){
            money = 2;
            showMeTheMoney();
        }
        public void showMeTheMoney(){
            System.out.println("I am Father, i have $" + money);
        }
    }

    static class Son extends Father{
        public int money = 3;
        public Son(){
            money = 4;
            showMeTheMoney();
        }
        public void showMeTheMoney(){
            System.out.println("I am Son, i have $" + money);
        }
    }

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

执行结果如下:

对执行结果的解释:

第一行:调用 Son 构造的时候,会先隐式调用父类构造,父类构造执行调用  showMeTheMoney 方法的时候,根据动态分派原理调用了 Son 的 重写方法,方法中对 money 的调用是 Son 的 money,值为0

第二行:相信大家都能理解

第三行:通过静态类型访问到了父类的 money,输出了2

以上内容来自《深入理解Java虚拟机》:JVM高级特性与最佳实践(第三版) 周志明著,8.3.2 节 分派

思考:子类的初始化动作 int money 在 Father() 之前执行(没有疑问,类加载器的初始化阶段),但是子类的 public in money = 3; 竟然在 Father() 之后执行,有知道的欢迎评论区讨论。

转载请在明显位置附上原文链接。


版权声明:本文为wf13265原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。