《深入拆解Java虚拟机》学习笔记 Day03

102 阅读3分钟

重载与重写

重载

重载的方法在编译过程中即可完成识别。 具体到每一个方法调用,Java 编译器会根据所传入参数的声明类型(注意与实际类型区分)来选取重载方法。

选取的过程共分为三个阶段: 1、在不考虑对基本类型自动装拆箱(auto-boxing,auto-unboxing),以及可变长参数的情况下选取重载方法;

2、如果在第 1 个阶段中没有找到适配的方法,那么在允许自动装拆箱,但不允许可变长参数的情况下选取重载方法;

3、如果在第 2 个阶段中没有找到适配的方法,那么在允许自动装拆箱以及可变长参数的情况下选取重载方法。

如果 Java 编译器在同一个阶段中找到了多个适配的方法,那么它会在其中选择一个最为贴切的,而决定贴切程度的一个关键就是形式参数类型的继承关系。


void invoke(Object obj, Object... args) { ... }
void invoke(String s, Object obj, Object... args) { ... }

invoke(null, 1);    // 调用第二个invoke方法
invoke(null, 1, 2); // 调用第二个invoke方法
invoke(null, new Object[]{1}); // 只有手动绕开可变长参数的语法糖,
                               // 才能调用第一个invoke方法

上面这串代码为例,当传入 null 时,它既可以匹配第一个方法中声明为 Object 的形式参数,也可以匹配第二个方法中声明为 String 的形式参数。由于 String 是 Object 的子类,因此 Java 编译器会认为第二个方法更为贴切。

除了同一个类中的方法,重载也可以作用于这个类所继承而来的方法。也就是说,如果子类定义了与父类中非私有方法同名的方法,而且这两个方法的参数类型不同,那么在子类中,这两个方法同样构成了重载。

重写

存在于父类和子类的同名方法。

如果这两个方法都是静态的,那么子类中的方法隐藏了父类中的方法。如果这两个方法都不是静态的,且都不是私有的,那么子类的方法重写了父类中的方法。

Java虚拟机如何识别方法

Java虚拟机识别方法的关键在于类名、方法名以及方法描述符。

方法描述符

方法描述符由方法的参数类型、返回类型构成。

在同一个类中,如果同时出现多个名字相同且描述符也相同的方法,那么虚拟机在类的验证阶段报错。

Java虚拟机对方法的重写基于方法描述符,即子类定义了与父类中非私有、非静态同名的方法,只有这两个方法的入参和出参类型一致,虚拟机才会判定重写。

静态绑定与动态绑定

静态绑定

指的是在解析时就能够识别目标方法。

动态绑定

指的是需要在运行过程中根据调用者的动态类型来识别目标方法。

Java字节码调用相关指令

invokestatic

用于调用静态方法

invokespecial

用于调用私有实例方法、构造器

invokevirtual

用于调用非私有实例方法

invokeinterface

用于调用接口方法

invokedynamic

用于调用动态方法。

参考文章:gk.link/a/11V4M