广东住房和城乡建设厅网站,网站招聘怎么做,重庆景点排行榜前十名,网站开发属于软件开发JAVA语言多态和动态语言实现原理 前言invoke指令invokestaticinvokespecialinvokevirtualinvokeintefaceinvokedynamicLambda 总结 前言
我们编码java文件#xff0c;javac编译class文件#xff0c;java运行class#xff0c;JVM执行main方法#xff0c;加载链接初始化对应… JAVA语言多态和动态语言实现原理 前言invoke指令invokestaticinvokespecialinvokevirtualinvokeintefaceinvokedynamicLambda 总结 前言
我们编码java文件javac编译class文件java运行classJVM执行main方法加载链接初始化对应类确定类/对象调用函数执行对应函数方法code字节码执行引擎不断取指执行。本文主要介绍虚拟机加载链接初始化类后在执行函数调用时虚拟机如何通过相关invoke指令确定具体执行函数并以此介绍JAVA语言中多态和动态语言实现原理。
invoke指令
虚拟机再实现函数调涉及invoke指令分为如下5类
invoke指令函数调用invokestatic执行类静态方法invokespecial执行对象构造器私有方法父类方法invokevirtual执行类对象的普通方法,非静态构造器私有方法等 虚拟机在运行期通过动态分派invokeinterface接口对象执行接口方法虚拟机在运行期通过动态分派invokedynamic用户编码确定方法句柄
下面代码分别演示编译后函数调用使用invoke指令使用jclasslib idea插件查看
public class InvokeTestDemo extends AbsParent implements InterfaceParent {public static void main(String[] args) throws Throwable{InvokeTestDemo demo new InvokeTestDemo();demo.test();}private void test() throws Throwable{// invokestatic 静态方法staticMethod();// invokespecial 构造方法new InvokeTestDemo();// invokespecial 私有方法privateMethod();// invokespecial 父类方法, 内部super.parentMethod();// invokevirtualfinalMethod();publicMethod();parentMethod();interfaceMethod();// invokeinterface 接口方法InterfaceParent iTest this;iTest.interfaceMethod();// invokedynamicFunctionString, String func str - append str;func.apply(test);// MethodHandleAnimal animal new Animal();say(animal);People people new People();say(people);}public static void say(Object obj) throws Throwable {MethodHandles.Lookup lookup MethodHandles.lookup();MethodType methodType MethodType.methodType(void.class);MethodHandle methodHandle lookup.findVirtual(obj.getClass(), say, methodType);methodHandle.invoke(obj);}public static class Animal {public void say() {System.out.println(hello Animal);}}public static class People {public void say() {System.out.println(hello People);}}public static void staticMethod() {}private void privateMethod() {}public final void finalMethod() {}public void publicMethod() {}Overridepublic void interfaceMethod() {}
}abstract class AbsParent {public void parentMethod() {}
}interface InterfaceParent {void interfaceMethod();
}invokestatic
调用类静态方法属于静态分派编译期可确定调用方法运行期不变。
invokespecial
调用对象构造器私有方法直接父类方法属于静态分派编译期可确定调用方法运行期不变。
invokevirtual
调用对象普通方法非对象构造器私有方法直接父类方法运行期根据对象具体类型再确定具体执行方法这个便是语言多态特征。
在具体实现上以HotSpot为例HotSpot使用了与C虚函数类似的机制同时为了避免每个对象都维护一个虚函数表设计了Oop-Klass模型用Klass类保存类的元数据和虚函数表vtable (virtual method table)。 vtable生成 1、递归生成父类vtable 2、覆盖重写方法 3、追加新定义方法
Class Animal {public void breathe() {}public void sound() {}}Class Cat extends Animal{overridepublic void sound() {}public void run() {}
}Animal vtable
方法方法地址breatheAnimal#breathesoundAnimal#sound
Cat vtable
方法方法地址备注breatheAnimal#breathe取自父类soundCat#sound本类重写soundCat#run本类追加
vtable是用空间换取时间类对应klass维护相对应的vtable发生函数调用时操作步骤如下 1、通过函数操作数栈获取栈顶调用函数者。 2、函数调用者查找实际类型class进而确定klass关联vtable。 3、通过函数编号找到vtable函数编号的方法代码code。 4、读取code字节码指令执行引擎执行指令。
invokeinteface
以接口调用接口类方法运行期根据接口实现类型再确定具体执行方法。
在具体实现上以HotSpot为例同vtable实现类似接口是使用itableinteface method table实现方法动态分派。
itable存储格式如下 itableOffsetEntry1 itableOffsetEntry2 …… itableOffsetEntryn itableMethodEntry1 itableMethodEntry2 …… itableMethodEntryn
itable函数查找过程如下 1、通过函数操作数栈获取栈顶调用函数者。 2、函数调用者查找实际类型class进而确定klass关联itable。 3、遍历itable查找接口entry对应itableOffsetEntry。 4、通过itableOffsetEntry
为什么需要itable,而不是用vtable去实现 1、一个类继承是单继承子类包含父类vtable且和父类的函数编号是一致可以直接使用父类的函数编号找到对应的子类实现函数。 2、一个类可以实现多个接口而每个接口的函数编号是个接口相关vtable无法解决多个对应接口的函数编号问题。 即虚拟机规范规定继承是单继承实现是可实现多个接口。
invokedynamic
以上介绍invoke指令调用的函数流程实现是在虚拟机内部编译器和虚拟机运行期完成调用方法查找并执行相应字节码而invokedynamic指令则支持由用户编码确定方法句柄具体查找过程如下 1、JVM执行到invokedynamic指令时它会首先查找与该指令关联的引导方法。 2、引导方法根据传入的参数动态生成和链接目标方法并返回CallSite对象封装了目标方法的所有信息包括方法句柄、参数类型和返回类型。 3、CallSite对象被创建并返回给invokedynamic指令JVM就会将该指令与调用站点对象关联起来。 4、在后续的执行过程中当再次遇到相同的invokedynamic指令时JVM会直接通过调用站点对象调用目标方法而无需再次执行引导方法。这种机制可以显著提高动态方法调用的性能。
某种意义上可以说invokedynamic指令与MethodHandle机制的作用是一样的。都是为了解决原有的4条”invoke”指令方法分派规则完全固化在虚拟机之中的问题。如何把查找目标方法的决定权从虚拟机转嫁到具体的用户代码中。
Lambda
lambda实现依赖invokedynamic执行由编译器生成引导方法生成调用点。 invokedynamic #13 apply, BootstrapMethods #0过程如下 1、Lambda 表达式解析常用引导方法java.lang.invoke.LambdaMetafactory#metaFactory 2、引导方法 metaMethod 根据这些参数生成 java.lang.invoke.CallSite 动态调用点 3、在引导方法中会动态生成一个模板匿名类 4、创建匿名类实例执行方法调用。
总结
多态特性虚拟机在运行时通过动态分派查找确定要执行函数。 动态语言虚拟机通过invokedynamic执行由应用程序指定MethodHanle确定函数调用者方法参数调用方法等实现动态语言。
参考 https://blog.csdn.net/weixin_47184173/article/details/109903542