本文转载自不使用反射如何调用某个实例对象的方法
导语
如何调用一个对象的方法?我们可以通过实例化对象直接调用、使用反射机制、通过代理对象等,本文介绍一种新的方法MethodHandle,这种方法在开发中很少会用到,但使用起来感觉很顺手。
什么是MethodHandle?
MethodHandle是JDK1.7实现了JSR-292,新加入的java.lang.invoke
包中的一个重要组成部分,这个包的主要是在单纯通过符号引用来确定调用的目标方法以外,提供一种析的动态确定目标方法的机制。
示例
package com.bk.exercise;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
/**
* @author BK
* @description:
* @date 2019-08-19 22:34
*/
public class MethodHandlerTest {
static class Person{
public void sing(String songName){
System.out.println("I'm sing " + songName);
}
}
/**
* 实现调用Person类的sing方法
* @param args
*/
public static void main(String[] args) throws Throwable {
Person zhangsan = new Person();
// void.class是方法返回的类型 String.class 是方法的入参类型
MethodType mt = MethodType.methodType(void.class,String.class);
MethodHandle handler = MethodHandles.lookup()
//找到zhangsan对象中签名和mt指定的签名是一致的sing方法
.findVirtual(zhangsan.getClass(), "sing", mt)
//非静态方法的第一个参数隐藏的this指针,这步相当设置第一个参数this指针
.bindTo(zhangsan);
handler.invokeExact("Summer train ");
}
}
运行结果如下显示
I'm sing Summer train
从示例可以看出来,使用MethodHandle并没有什么困难,可以实现方法的调用,可是很多人会问,反射不也可以做相同的事情么,我们经常会使用反射,而不会使用这种方法。
MethodHandle与Reflection的区别
如果站在Java语言的角度来看,他们确实是有很多相似之处,但是从他们其它角度来看,确有很大的区别
- 从本质上来讲,
Reflection
和MethodHandle
机构都是在模拟方法调用,但Reflection是模拟的Java代码层面的方法调用,而MethodHandle是在模拟字节码层面的方法调用。 Reflection
中的Method是重量级的,MethodHandle
对象是轻量级的,Reflection中包含了方法的签名、描述符以及方法属性表中各种属性、执行权限等,而MethodHandle
仅仅包含与执行该方法相关的信息MethodHandle
是字符码的方法指令调用模拟,理论上可以模拟出和JVM上一样的优化如方法内联,但是Reflection
去调用方法则不可以Reflection API
的设计目标是为Java语言服务
的,而MethodHandle
设计成可服务于所有Java虚拟机之上
的语言
写在最后
MethodHandles.lookup中的findStatic()
、findVirtual()
、findSpecia()
三个谅正是为了对应invokestatic
、invokevirtual&invokeinterface
、invokespecial这几条字节码指令的执行权限校验行为,本文中只讲到了findVirtual()方法,其它两个方法读者可以自行尝试一下。
java.lang.invoke
包中的内容可以看一看,别有一番有洞天。