摘要:学习添加一个字节码。使用提供了字节码的支持。这个启动方法的返回值是类的对象。与区别在模拟字节码层次的方法调用,因而可适用于所有语言在模拟层次的方法调用,仅可适用于。方法调用需要考虑到字节码,而则不用考虑这些。
JSR 292 学习
Add a new bytecode, invokedynamic ,
that supports efficient and flexible execution of method invocations in the absence of static type information.
添加一个字节码 invokedynamic 。用于提供在缺乏静态类型信息时高效和灵活的执行方法调用。
invokedynamic 是针对 JVM 的,用于更好的支持动态 JVM 语言的函数调用; JSR292 实现则提供在 Java 语言层面上的 invokedynamic 调用。
JSR292 实现于 JDK7,以下为实现方案的类。
└─java └─lang ├─invoke | ├─CallSite | ├─ConstantCallSite | ├─MethodHandle | ├─MethodHandleProxies | ├─MethodHandles | ├─MethodHandles.Lookup | ├─MethodType | ├─MutableCallSite | ├─SwitchPoint | └─VolatileCallSite ├─ClassValue └─BootstrapMethodErrorAPI 使用
JSR292 API 提供了 invokedynamic 字节码的 API 支持。使用基本思路
创建 MethodType 对象,指定方法的签名
在 MethodHandles.Lookup 中查找类型为 MethodType 的 MethodHandle
传入方法参数并调用 MethodHandle.invoke 或者 MethodHandle.invokeExact 方法
MethodType用于指定方法的类型,此处的方法类型与 Java 的方法判断有点区别,Java 的方法签名不包括 返回值 ,但是 MethodType 却是通过 返回值 和 参数类型 来确定。并且该类型不包含 方法名 。
// 快速创建一个 MethodType 。 MethodType methodType = MethodType.methodType(String.class, Object.class); // 也可以通过 MethodHandle 实例获取它要调用的方法实例 // MethodHandle handle = ... MethodType type = handle.type();
除了这两种获取 MethodType 的方法(实际上第二种不算,MethodHandle 对象的创建依赖于 MethodType)。下面还有两种,它也是 MethodType 的静态方法:
genericMethodType: 所有类型都是 Object 类型
fromMethodDescriptorString: 有两个参数,一个是方法描述符,该描述符是基于 字节码 层面的描述符。之后就是一个类加载器。
当然,创建完之后还可以修改返回值类型和参数类型如: changeParameterType 、 changeReturnType 等。
MethodHandles.Lookup一个工厂类,用于创建 MethodHandle 类对象。它可通过普通的 findXxx() 方法得到相应的 MethodHandle 实例,也可以通过 反射类 来创建实例。如 lookup.unreflect(Method) 等方法。
MethodHandleMethodHandle 可看成是方法引用,它使得 Java 拥有了类似函数指针或委托的方法别名工具。
注意几点:
引用的方法必须和 MethodHandle 的 type 保持一致。
这里提到的 type 包括 返回值 和 参数列表 。
MethodHandle 也是可执行及可以进行转换。
几个 MethodHandle 方法与字节码的对应:
MethodHandle方法 | 字节码 | 描述 |
---|---|---|
findStatic | invokestatic | 调用静态方法 |
findSpecial | invokespecial | 调用实例构造方法,私有方法,父类方法。 |
findVirtual | invokevirtual | 调用所有的虚方法 |
findVirtual | invokeinterface | 调用接口方法,会在运行时再确定一个实现此接口的对象。 |
示例
public void example() throws Throwable { // MethodHandles.Lookup 类似于 MethodHandle 工厂类,用于创建 MethodHandle MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle mh = lookup.findStatic(String.class, "valueOf", MethodType.methodType(String.class, int.class)); String result = (String) mh.invoke(1); System.out.println("1".equals(result)); }
三种调用方式:
invokeExact: 调用此方法与直接调用底层方法一样,需要做到参数类型精确匹配
invoke: 参数类型松散匹配,通过asType自动适配
invokeWithArguments: 直接通过方法参数来调用
CallSite当 JVM 执行 invokedynamic 指令时,首先需要链接其对应的 动态调用点 。在链接的时候,JVM会先调用一个启动方法(bootstrap method)。这个启动方法的返回值是 java.lang.invoke.CallSite 类的对象。
在通过启动方法得到了 CallSite 之后,通过这个 CallSite 对象的 getTarget() 可以获取到实际要调用的目标方法句柄。
有了方法句柄之后,对这个 动态调用点 的调用,实际上是代理给方法句柄来完成的。
也就是说,对 invokedynamic 指令的调用实际上就等价于对方法句柄的调用,具体来说是被转换成对方法句柄的invoke方法的调用。
JDK7 中提供了三种类型的动态调用点CallSite的实现:java.lang.invoke.ConstantCallSite、java.lang.invoke.MutableCallSite和 java.lang.invoke.VolatileCallSite。
ConstantCallSite表示的调用点绑定的是一个固定的方法句柄,一旦链接之后,就无法修改。示例如下:
public void constantCallSite() throws Throwable { MethodType type = MethodType.methodType(String.class, int.class, int.class); MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle handle = lookup.findVirtual(String.class, "substring", type); ConstantCallSite callSite = new ConstantCallSite(handle); MethodHandle invoker = callSite.dynamicInvoker(); String result = (String) invoker.invoke("Hello", 2, 3); System.out.println(result); }MutableCallSite
表示的调用点则允许在运行时动态修改其目标方法句柄,即可以重新链接到新的方法句柄上。示例如下:
/** * MutableCallSite 允许对其所关联的目标方法句柄通过setTarget方法来进行修改。 * 以下为 创建一个 MutableCallSite,指定了方法句柄的类型,则设置的其他方法也必须是这种类型。 */ public void useMutableCallSite() throws Throwable { MethodType type = MethodType.methodType(int.class, int.class, int.class); MutableCallSite callSite = new MutableCallSite(type); MethodHandle invoker = callSite.dynamicInvoker(); MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle maxHandle = lookup.findStatic(Math.class, "max", type); callSite.setTarget(maxHandle); int result = (int) invoker.invoke(3, 5); System.out.println(result == 5); MethodHandle minHandle = lookup.findStatic(Math.class, "min", type); callSite.setTarget(minHandle); result = (int) invoker.invoke(3, 5); System.out.println(result == 3); }
MutableCallSite.syncAll() 提供了方法来强制要求各个线程中 MutableCallSite 的使用者立即获取最新的目标方法句柄。
但这个时候也可以选择使用 VolatileCallSite。
作用与 MutableCallSite 类似,不同的是它适用于多线程情况,用来保证对于目标方法句柄所做的修改能够被其他线程看到。
此处便不再提供示例,可参考 MutableCallSite。
MethodHandle 在模拟 字节码 层次的方法调用,因而可适用于所有 JVM 语言 ;Reflection 在模拟 Java 层次的方法调用,仅可适用于 Java。
MethodHandle 可进行 JVM 的内联优化,Reflection 屏蔽了 JVM ,所以完全没有相应的优化。
MethodHandle 从 JVM 层次支持调用,只需要包含方法必要的信息,所以说是轻量级的,而 Reflection 是 Java Api 层次的反射调用,包含了方法的签名、描述符以及方法属性表中各种属性的Java端表示方式,还包含有执行权限等的运行期信息,所以说是重量级的。
MethodHandle 方法调用需要考虑到 字节码,而 Reflection 则不用考虑这些。
参考JDK1.8下关于MethodHandle问题
Invokedynamic 和 MethodHandle的缘由
MethodHandle与反射Method区别
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/72496.html
摘要:物联网已经成为现实只要去年单独参加过会议或者搜索过专门的技术网站,你现在会越来越清楚地注意到物物互联正在蓬勃发展。有大量的讨论在口头上承认了物联网,年这方面的激烈讨论只会更多。两年过去了,期待已久的更新应该在月日发布。 导读 如果你还在为Oracle收购Sun公司给Java社区的变化所纠结,请站在Oracle的角度替它想想吧。2013年大部分时间里,Oracle都在与遗留的Java安...
摘要:摘要添加了表达式闭包和特性支持,包括方法的引用,增强类型推断,和虚拟扩展方法。围绕的语言功能支持包括虚拟扩展方法,这将使接口的源代码和二进制兼容的方式演变升级。 Author:Joseph D. Darcy Organization:Oracle Owner:Brian Goetz Created:2011/11/1 Updated:2013/2/21 Type:Feature Sta...
摘要:概述是一个主要版本的发布这里介绍的是对的特性和增强的实现是的增强提案,包括增强建议和路线图流程规范请求,描述了针对平台的建议和最终规范主要变更统一模块化标准这是全新的编程组件模块,是可命名的可自描述的代码和数据集合。 概述 java9是一个主要版本的发布 这里介绍的是Oracle对JDK9的特性和增强的实现 JEP是JDK的增强提案,包括增强建议和路线图流程 JSR(Java规范请...
阅读 1534·2023-04-26 02:50
阅读 3534·2023-04-26 00:28
阅读 1931·2023-04-25 15:18
阅读 3208·2021-11-24 10:31
阅读 985·2019-08-30 13:00
阅读 999·2019-08-29 15:19
阅读 1765·2019-08-29 13:09
阅读 2974·2019-08-29 13:06