首页 > 其他分享 >使用MethodHandles来调用

使用MethodHandles来调用

时间:2023-11-07 15:03:44浏览次数:25  
标签:MethodHandles 调用 java String invoke 使用 方法 class

在Java中,我们想在程序运行时调用其方法,可以用JDK提供的反射相关API来实现,代码如下:

Class clazz = Demo.class;
Method method = clazz.getMethod("studyHard", new Class[]{String.class});
Demo demo = clazz.newInstance();
method.invoke(demo, "哈哈");

这样的代码看起来也挺简洁,不过在JDK7之后,提供了java.lang.invoke.MethodHandle,它的功能与反射相似,下面是一个例子:

public class Demo {

    public String test1(int a, String b) {
        System.out.println("test1 -> " + a + b);
        return a + b;
    }

    public static String test2(int a, String b) {
        System.out.println("test2 -> " + a + b);
        return a + b;
    }

    public static void main(String[] args) throws Throwable {
        Class<?> clazz = Demo.class;
        MethodType signature = MethodType.methodType(String.class, int.class, String.class);
        MethodHandle mh = MethodHandles.lookup().findVirtual(clazz, "test1", signature);

        Object obj = clazz.getConstructor().newInstance();
        System.out.println(mh.bindTo(obj).invoke(1, "2"));
        System.out.println((String)mh.bindTo(obj).invokeExact(1, "2"));

        //--------------静态方法
        MethodHandle mh2 = MethodHandles.lookup().findStatic(clazz, "test2", signature);
        System.out.println(mh.bindTo(obj).invoke(1, "2"));
    }
}

从例子可以看出,我们先要通过MethodType来生成方法的签名,比如方法的参数类型,方法的返回值类型等。

MethodType signature = MethodType.methodType(String.class, int.class, String.class);

有了方法的签名,我们就可以利用方法签名、方法名称以及该方法所在的类来获取方法句柄(MethodHandle),代码如下:

 MethodHandle mh = MethodHandles.lookup().findVirtual(clazz, "test1", signature);

此时需要MethodHandles.lookup()静态方法来查找上下文对象,查找上下文对象有一些以“find”开头的方法,例如,findVirtual()、findSpecial()、findStatic()等。这些方法将会返回实际的方法句柄。

MethodHandle要先bindTo到某个对象实例上,然后调用invoke方法,传入参数就可以调用了。注意还有一个invokeExact方法,该方法与invoke方法的区别是方法参数、返回值匹配非常严格,调用时如果有数值参数隐式转换(如short转int/子类转父类)、装箱拆箱,会直接抛异常。比如函数返回值没有强制转换为String类型,就会抛异常:

Exception in thread "main" java.lang.invoke.WrongMethodTypeException: expected (int,String)String but found (int,String)Object
	at java.base/java.lang.invoke.Invokers.newWrongMethodTypeException(Unknown Source)
	at java.base/java.lang.invoke.Invokers.checkExactType(Unknown Source)
	at MethodHandles/me.mingshan.demo.Demo.main(Demo.java:26)

从目前接触到的API来看,似乎和以前用的反射区别并不大,其实不然,上面的特性包含在JSR 292中,提供了比反射API更加强大的动态方法调用能力,并且新增了一个java虚拟机指令invokedynamicinvokedynamic指令通过引导方法(bootstrap method,BSM)机制来使用方法句柄。有关该指令更详细的信息可以参考Java虚拟机规范。

另外,在JDK9中新增了Variable Handles(变量句柄)相关功能,主要是用来取代java.util.concurrent.atomic包以及sun.misc.Unsafe类的功能,在Lookup类中,新增了findVarHandle方法来获取变量句柄,提供了各种细粒度的原子或有序性操作,更加安全和性能更高,毕竟sun.misc.Unsafe以后不推荐使用了,不安全。

参考:


title: Use MethodHandles To Invoke
tags: [MethodHandles, java]
author: Mingshan
categories: Java
date: 2018-10-02

标签:MethodHandles,调用,java,String,invoke,使用,方法,class
From: https://www.cnblogs.com/mingshan/p/17793627.html

相关文章

  • selenium等待元素加载,元素操作,执行js,切换选项卡,前进后退,异常处理,登录cnblogs,抽
    1selenium等待元素加载......
  • python虚拟环境的使用笔记
    方法一:在后台手动安装1、输入命令:pip3installvirtualenv2、指定目录:cd....;然后输入:virtualenvenv_django(创建虚拟环境) 3、激活该虚拟环境:      windows进到目录里,的Script文件夹输入:activate       linux:soruseenv1/Script/activate ......
  • Openmv简明使用教程
    Openmv简明使用教程写在前面本教程主要目的是指明学习资源在哪,可以怎么学,不教具体怎么使用,因为没有什么教程比官网上的教程更详细了,希望大家看完这篇文章后,能对如何学习使用Openmv有一个清晰的认知。一、Openmv介绍​ OpenMV是一个开源,低成本,功能强大的机器视觉模块。​ ......
  • 关于fieldMask在go项目使用
    介绍: NetflixAPI设计实践:使用FieldMask(qq.com)该文章,详述了关于proto中,使用fieldMask的背景及收益,还有具体example提供参考。接下来,需要考虑在go项目中的使用。主要为以下几方面:1.服务端需要提供新的proto文件2.客户端需要感知这些proto文件,且需要关注声明为fiel......
  • springboot nacos使用yaml配置list方式
    方式一配置项:app:demo:list1:xiaohong,xiaominglist2:>xiaohong,xiaominglist1和list2看起来是2种风格,其实都是同一种写法,以逗号分隔java代码:@Data@ComponentpublicclassAppConfig1{@Value("${app.demo.list1}")privateList<Strin......
  • mysql测试语句创建写入存储过程调用8.0
    --创建表格 CREATETABLEmy_table(idINTAUTO_INCREMENT,nameVARCHAR(255)CHARACTERSETutf8mb4COLLATEutf8mb4_0900_ai_ci,emailVARCHAR(255)CHARACTERSETutf8mb4COLLATEutf8mb4_0900_ai_ci,passwordVARCHAR(255)CHARACTERSETutf8mb4COLL......
  • 解决mybatis嵌套查询使用PageHelper分页不准确
    版权声明:本文为CSDN博主「那只小猿」的原创文章,遵循CC4.0BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/weixin_41869361/article/details/116427385springboot项目中嵌套查询使用PageHelper发现使用结果不正确,上PageHelper官网看了一下果然是......
  • rasmol使用方法
    rasmol软件简介及详细使用说明:目前在结构生物学领域有许多图形显示的程序,每个都有自己不同的特点。可能很多人知道rasmol,除了图形界面中的一些功能外,该程序的命令行方式有着很强大的功能。下面将介绍一些常用的使用方法。Rasmol(http://www.openrasmol.org/)程序有多种版本,有u......
  • 如何使用phpstorm调试php
    以前调试php都是使用dump或者var_dump来进行,非常不方便,现在可以使用phpstorm来进行动态调试,单步跟踪等,可以更快完成任务,环境为本地是win10,ip地址为192.168.0.114服务器使用虚拟机centos7,ip地址为192.168.115.1201.服务器安装xdebug扩展,如果服务器使用了宝......
  • Python中\t代表什么?如何使用?
    在Python中,\t代表制表符,代表着四个空格,也就是一个tab,它的主要作用是对齐表格数据的各列,使得输出更易于阅读和理解。那么Python中\t代表什么?如何使用?我们来看看详细内容介绍。在Python中,\t是一个转义字符序列,它代表了一个水平制表符。水平制表符可以将文本对齐到特定的列,......