MethodHandle(方法句柄)系列之二:方法句柄的简单使用

二话不说,上代码

/**
 *
 * @author LiuYeFeng<[email protected]>
 * @date 2015年4月8日 下午10:41:13
 * @CopyRight 2015 TopView Inc
 * @version V1.0
 */
public class MethodHandleTest {

    public MethodHandle getHandler() {
        MethodHandle mh = null;
        MethodType mt = MethodType.methodType(String.class, int.class, int.class);
        MethodHandles.Lookup lk = MethodHandles.lookup();

        try {
            mh = lk.findVirtual(String.class, "substring", mt);
        } catch (Throwable e) {
            e.printStackTrace();
        }

        return mh;
    }

    public static void main(String[] args) throws Throwable {
        MethodHandle mh = new MethodHandleTest().getHandler();
        String str = "hello world";

        Object result1 = mh.invoke(str, 1, 3);
        Object result2 = (String) mh.invokeExact(str, 1, 3);
//      Object result2 = mh.invokeExact(str, new Integer(1), 3);
        /**
         * 上面这句方法执行时报错,因为方法类型为String.class, int.class, int.class
         * 而返回的类型为Object,与声明中为String不符合
         * 其中第二个参数类型为Integer,与声明中为int不符合,则类型适配不符合,系统报错。
         */

        System.out.println("result 1:" + result1);
        System.out.println("result 1:" + result2);
    }
}

  代码输出结果均为el。

接下来说一下方法句柄的调用过程,首先,在获取方法句柄之前,先通过MethodType的静态工厂方法,先生成一个包含方法参数类型、方法返回类型的的方法类型,也就是MethodType mt = MethodType.methodType(String.classint.classint.class)。

    其次,获取方法句柄要用到Lookup对象,比如代码中的MethodHandles.Lookup lk,这个对象可以提供其所在环境中任何可见方法的方法句柄。我们可以将其比喻成包含有某个类对象的方法成员、方法的容器,通过lk.findVirtual(String.class"substring", mt);具体锁定String类型中的某个方法,作为方法句柄返回。要从lookup对象中得到方法句柄,需要给出持有所需方法的类,方法的名称,以及跟方法相匹配的方法类型。

    最后,获取到方法句柄后,我们就可以通过方法句柄来调用底层的方法,这点上,跟反射中的方法调用类似。方法句柄提供两个方法调用底层方法,invoke和invokeExact方法。invokeExact方法与直接调用底层方法是一样的,比如代码中,mh.invoke(str, 1, 2)就相当于直接调用str.substring(1, 3);具体两个方法的区别下面再说。这里先解析一下这两个方法的调用,方法的调用参数基本都一样,第一个参数为方法的接受对象,即是哪个对象执行这个方法,接下来的参数就是执行方法所需要的参数。当然第一个参数,也就是方法的接受对象,可以通过方法句柄的bindto动态的参数绑定方法来绑定,从而使方法句柄的调用和普通方法调用没区别,动态的参数绑定我们以后再研究。

    这里需要强调一下,静态方法和动态方法之间的差别,静态方法是不需要制定方法的接受对象的,而一般方法是需要的。

 

 

参考资料:《java程序员修炼之道》、《深入理解java7核心技术与最佳实践》

时间: 2024-10-01 07:11:21

MethodHandle(方法句柄)系列之二:方法句柄的简单使用的相关文章

SequoiaDB 系列之二 :SequoiaDB的简单CRUD操作

上一篇通过一系列的操作,终于把SequoiaDB的集群部署到单台机器上了. 建议去安装体验一下吧. 在整个环境的部署的体验来看,并没有MongoDB的部署简单,但是比MongoDB的部署要清晰.MongoDB启动进程,后面跟着一大串配置,有点云里雾里的感觉,这个对初学者不太友好.而SequoiaDB的部署,着眼整个集群环境,能在脑中轻松构建一副设计图,协调节点的服务端口是11810,catalog节点的服务端口是11820,11830,11840,而数据节点的服务端口是11850,11860,1

初识Redis系列之二:安装及简单使用

仅介绍windows下的安装 一:下载地址:https://github.com/MSOpenTech/redis/releases. Redis 支持 32 位和 64 位.这个需要根据你系统平台的实际情况选择,这里我们下载 Redis-x64-xxx.zip压缩包并解压. 这里我把文件夹重命名为redis,存放在C盘根目录,方便后面测试 二:起一个服务端 打开一个 cmd 窗口,使用cd命令切换目录到 C:\redis, 运行 redis-server.exe redis.windows.c

WebService系列(二)--WSDl File简单举例

1:新建java项目 2:新建一个包,用来存放待会生成的类 3:新建文件 wsdl 4:wsdl文件命名,用的是哪个service,就用谁来命名,这里用手机的MobileCodeWS 5:点击finish,文件生成 http://www.webxml.com.cn/WebServices/WeatherWebService.wsdl 6:生成的文件除了头文件 <?xml version="1.0" encoding="UTF-8" standalone=&qu

无法获得VMCI 驱动程序的版本: 句柄无效。解决方法

关闭虚拟机,找到安装路径,用记事本打开.vmx结尾的文件 找到vmci0.present = "TRUE" 把TRUE改为FALSE,保存,再次打开虚拟机,问题解决. 无法获得VMCI 驱动程序的版本: 句柄无效.解决方法

Dagger2系列之使用方法

本系列只讲使用方法和使用中遇到的问题,如果还对dagger2还不了解的童鞋儿可以参考文章: http://www.jianshu.com/p/cd2c1c9f68d4 http://www.jianshu.com/p/94d47da32656 使用Dagger2的前提需要添加一些依赖: 1 在Project的 build.gradle文件添加以下内容 buildscript { repositories { jcenter() } dependencies { classpath 'com.an

设计模式总结篇系列:工厂方法模式(Factory Method)

工厂方法模式适合于对实现了同一接口或继承了同一父类的一些类进行实例的创建.一般是通过定义一个工厂类,并在其方法中实现对具有上述特点的类对象的创建. 根据具体产生类对象的方法定义形式,又可以将其分为普通工厂方法模式.多个工厂方法模式和静态工厂方法模式. 一.普通工厂方法模式: 常见的经典写法如下(以发送邮件和短信为例): 1.定义邮件类和短信类具有的共同接口: 1 interface Sender{ 2 3 public void sender(); 4 5 } 2.定义邮件类和短信类: 1 cl

pandas.DataFrame学习系列2——函数方法(1)

DataFrame类具有很多方法,下面做用法的介绍和举例. pandas.DataFrame学习系列2--函数方法(1) 1.abs(),返回DataFrame每个数值的绝对值,前提是所有元素均为数值型 1 import pandas as pd 2 import numpy as np 3 4 df=pd.read_excel('南京银行.xlsx',index_col='Date') 5 df1=df[:5] 6 df1.iat[0,1]=-df1.iat[0,1] 7 df1 8 Open

小酌重构系列[4]&mdash;&mdash;分解方法

概述 "分解方法"的思想和前面讲到的"提取方法"."提取方法对象"基本一致.它是将较大个体的方法不断的拆分,让每个"方法"做单一的事情,从而提高每个方法的可读性和可维护性.分解方法可以看做是"提取方法"的递归版本,它是对方法反复提炼的一种重构策略. 分解方法 下图表示了这个重构策略,第1次提炼和第2次提炼都采用了"提取方法"这个策略. 何时分解方法? "分解方法"最终

Java学习-025-类名或方法名应用之二 -- 统计分析基础

前文讲述了类名或方法的应用之一调试源码,具体请参阅:Java学习-025-类名或方法名应用之一 -- 调试源码 此文主要讲述类名或方法应用之二统计分析,通过在各个方法中插桩(调用桩方法),获取方法的调用关系.通过调用关系,我们可以统计出被调用次数比较多的方法,同时也可以构建全系统调用关系链:通过操作重要业务流程,可以统计组成重要业务流程的主要方法,加强相应的单元测试.功能.安全.性能等方面的测试.对于软件产品质量控制存在非凡的意义. 下面构建的演示示例调用关系如下所示: GetClassMeth