资讯专栏INFORMATION COLUMN

JSR 292 学习

mochixuan / 347人阅读

摘要:学习添加一个字节码。使用提供了字节码的支持。这个启动方法的返回值是类的对象。与区别在模拟字节码层次的方法调用,因而可适用于所有语言在模拟层次的方法调用,仅可适用于。方法调用需要考虑到字节码,而则不用考虑这些。

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
        └─BootstrapMethodError
API 使用
JSR292 API 提供了 invokedynamic 字节码的 API 支持。
使用基本思路

创建 MethodType 对象,指定方法的签名

MethodHandles.Lookup 中查找类型为 MethodTypeMethodHandle

传入方法参数并调用 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: 有两个参数,一个是方法描述符,该描述符是基于 字节码 层面的描述符。之后就是一个类加载器。

当然,创建完之后还可以修改返回值类型和参数类型如: changeParameterTypechangeReturnType 等。

MethodHandles.Lookup

一个工厂类,用于创建 MethodHandle 类对象。它可通过普通的 findXxx() 方法得到相应的 MethodHandle 实例,也可以通过 反射类 来创建实例。如 lookup.unreflect(Method) 等方法。

MethodHandle

MethodHandle 可看成是方法引用,它使得 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.ConstantCallSitejava.lang.invoke.MutableCallSitejava.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

VolatileCallSite

作用与 MutableCallSite 类似,不同的是它适用于多线程情况,用来保证对于目标方法句柄所做的修改能够被其他线程看到。
此处便不再提供示例,可参考 MutableCallSite

MethodHandle 与 Method 区别

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

相关文章

  • 2014年Java值得期待的五大理由

    摘要:物联网已经成为现实只要去年单独参加过会议或者搜索过专门的技术网站,你现在会越来越清楚地注意到物物互联正在蓬勃发展。有大量的讨论在口头上承认了物联网,年这方面的激烈讨论只会更多。两年过去了,期待已久的更新应该在月日发布。 导读 如果你还在为Oracle收购Sun公司给Java社区的变化所纠结,请站在Oracle的角度替它想想吧。2013年大部分时间里,Oracle都在与遗留的Java安...

    tinyq 评论0 收藏0
  • Java8 新特性:Lambda表达式和虚拟扩展方法标注

    摘要:摘要添加了表达式闭包和特性支持,包括方法的引用,增强类型推断,和虚拟扩展方法。围绕的语言功能支持包括虚拟扩展方法,这将使接口的源代码和二进制兼容的方式演变升级。 Author:Joseph D. Darcy Organization:Oracle Owner:Brian Goetz Created:2011/11/1 Updated:2013/2/21 Type:Feature Sta...

    UsherChen 评论0 收藏0
  • Java7的新特性

    摘要:语言特性系列的新特性的新特性的新特性的新特性的新特性的新特性的新特性的新特性的新特性序本文主要讲的新特性,相对于而言,增加了一些重要的特性,比如,不像那么鸡肋,也算是一个重要的版本。其他支持的下划线支持参考 Java语言特性系列 Java5的新特性 Java6的新特性 Java7的新特性 Java8的新特性 Java9的新特性 Java10的新特性 Java11的新特性 Java12...

    April 评论0 收藏0
  • JDK 9 变更一览

    摘要:概述是一个主要版本的发布这里介绍的是对的特性和增强的实现是的增强提案,包括增强建议和路线图流程规范请求,描述了针对平台的建议和最终规范主要变更统一模块化标准这是全新的编程组件模块,是可命名的可自描述的代码和数据集合。 概述 java9是一个主要版本的发布 这里介绍的是Oracle对JDK9的特性和增强的实现 JEP是JDK的增强提案,包括增强建议和路线图流程 JSR(Java规范请...

    sherlock221 评论0 收藏0
  • SpringBoot2.0深度实践学习手记

    SpringBoot易学 组件自动装配:规约大于配置,专注于核心业务外部化配置:一次构建、按需调配,到处运行 嵌入式容器:内置容器、无需部署、独立运行 Spring Boot Starter : 简化依赖、按需装配、自我包容 Production-Ready : 一站式运维、生态无缝整合 SpringBoot难精 组件自动装配:模式注解、@Enable模块、条件装配、加载机制外部化配置:Envi...

    赵连江 评论0 收藏0

发表评论

0条评论

mochixuan

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<