java methodhandle_java7 java MethodHandle解析

简介

JDK6之前我们会使用java反射来实现动态方法调用,多数框架用反射的比较多,例如mybatis、spring等。在JDK7中,新增了java.lang.invoke.MethodHandle(方法句柄),称之为“现代化反射”。其实反射和java.lang.invoke.MethodHandle都是间接调用方法的途径,但java.lang.invoke.MethodHandle比反射更简洁,用反射功能会写一大堆冗余代码。

官方api给出的解释:

A method handle is a typed, directly executable reference to an underlying method, constructor, field, or similar low-level operation, with optional transformations of arguments or return values.其实就是可以获取方法的句柄,类似方法的指针。

下面看一个例子,使用方法句柄(MethodHandle)调用toString()方法:

packageorg.zwc.methodhandletest;importjava.lang.invoke.MethodHandle;importjava.lang.invoke.MethodHandles;importjava.lang.invoke.MethodType;public classMHTest {publicString toString(String s) {return "hello," + s + "MethodHandle";

}public static voidmain(String[] args) {

MHTest mhTest= newMHTest();

MethodHandle mh= getToStringMH(); //获取方法句柄

try{//1.调用方法:

String result = (String) mh.invokeExact(mhTest, "ssssss"); //根据方法句柄调用方法----注意返回值必须强转

System.out.println(result);

}catch(Throwable throwable) {

throwable.printStackTrace();

}//2.or like this:

try{

MethodHandle methodHandle2=mh.bindTo(mhTest);

String toString2= (String) methodHandle2.invokeWithArguments("sssss");

System.out.println(toString2);

}catch(Throwable throwable) {

throwable.printStackTrace();

}//得到当前Class的不同表示方法,最后一个最好。一般我们在静态上下文用SLF4J得到logger用。

System.out.println(MHTest.class);

System.out.println(mhTest.getClass());

System.out.println(MethodHandles.lookup().lookupClass());//like getClass()

}/*** 获取方法句柄

*@return

*/

public staticMethodHandle getToStringMH() {

MethodType mt= MethodType.methodType(String.class, String.class); //获取方法类型 参数为:1.返回值类型,2方法中参数类型

MethodHandle mh= null;try{

mh= MethodHandles.lookup().findVirtual(MHTest.class, "toString", mt); //查找方法句柄

} catch (NoSuchMethodException |IllegalAccessException e) {

e.printStackTrace();

}returnmh;

}

}

执行结果:

hello,ssssssMethodHandle

hello,sssssMethodHandleclassorg.zwc.methodhandletest.MHTestclassorg.zwc.methodhandletest.MHTestclass org.zwc.methodhandletest.MHTest

java7在JSR 292中增加了对动态类型语言的支持,使Java也可以像C语言那样将方法作为参数传递,其实现在lava.lang.invoke包中。MethodHandle作用类似于反射中的Method类,但它比Method类要更加灵活和轻量级。通过MethodHandle进行方法调用一般需要以下几步:

(1)创建MethodType对象,指定方法的签名;

(2)在MethodHandles.Lookup中查找类型为MethodType的MethodHandle;

(3)传入方法参数并调用MethodHandle.invoke或者MethodHandle.invokeExact方法。

MethodType

可以通过MethodHandle类的type方法查看其类型,返回值是MethodType类的对象。也可以在得到MethodType对象之后,调用MethodHandle.asType(mt)方法适配得到MethodHandle对象。可以通过调用MethodType的静态方法创建MethodType实例,有三种创建方式:

(1)methodType及其重载方法:需要指定返回值类型以及0到多个参数;

(2)genericMethodType:需要指定参数的个数,类型都为Object;

(3)fromMethodDescriptorString:通过方法描述来创建。

创建好MethodType对象后,还可以对其进行修改,MethodType类中提供了一系列的修改方法,比如:changeParameterType、changeReturnType等。

Lookup

MethodHandle.Lookup相当于MethodHandle工厂类,通过findxxx方法可以得到相应的MethodHandle,还可以配合反射API创建MethodHandle,对应的方法有unreflect、unreflectSpecial等。

invoke

在得到MethodHandle后就可以进行方法调用了,有三种调用形式:

(1)invokeExact:调用此方法与直接调用底层方法一样,需要做到参数类型精确匹配;

(2)invoke:参数类型松散匹配,通过asType自动适配;

(3)invokeWithArguments:直接通过方法参数来调用。其实现是先通过genericMethodType方法得到MethodType,再通过MethodHandle的asType转换后得到一个新的MethodHandle,最后通过新MethodHandle的invokeExact方法来完成调用。

附MethodHandle作为参数的示例代码:

packagecom.sun.jojo.methodhandle;importjava.lang.invoke.MethodHandle;importjava.lang.invoke.MethodHandles;importjava.lang.invoke.MethodType;importjava.util.Arrays;importjava.util.List;public classMethodHandleTest {public static void main(String[] args) throwsThrowable {

MethodHandles.Lookup lookup=MethodHandles.lookup();

MethodHandle methodHandle= lookup.findStatic(MethodHandleTest.class,"doubleVal", MethodType.methodType(int.class,int.class));

List dataList = Arrays.asList(1, 2, 3, 4, 5);

MethodHandleTest.transform(dataList,methodHandle);for(Integer data : dataList) {

System.out.println(data);//2,4,6,8,10

}

}public static List transform(List dataList, MethodHandle handle) throwsThrowable {for (int i = 0; i < dataList.size(); i++) {

dataList.set(i, (Integer) handle.invoke(dataList.get(i)));//invoke

}returndataList;

}/*** 作为参数的方法

*@paramval

*@return

*/

public static int doubleVal(intval) {return val * 2;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值