不使用反射如何调用某个实例对象的方法

如何调用一个对象的方法?我们可以通过实例化对象直接调用、使用反射机制、通过代理对象等,本文介绍一种新的方法MethodHandle,这种方法在开发中很少会用到,但使用起来感觉很顺手。

什么是MethodHandle?

MethodHandle是JDK1.7实现了JSR-292,新加入的java.lang.invoke包中的一个重要组成部分,这个包的主要是在单纯通过符号引用来确定调用的目标方法以外,提供一种析的动态确定目标方法的机制。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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 ");
}
}

运行结果如下显示

1
I'm sing Summer train

从示例可以看出来,使用MethodHandle并没有什么困难,可以实现方法的调用,可是很多人会问,反射不也可以做相同的事情么,我们经常会使用反射,而不会使用这种方法。

MethodHandle与Reflection的区别

如果站在Java语言的角度来看,他们确实是有很多相似之处,但是从他们其它角度来看,确有很大的区别

  1. 从本质上来讲,ReflectionMethodHandle机构都是在模拟方法调用,但Reflection是模拟的Java代码层面的方法调用,而MethodHandle是在模拟字节码层面的方法调用。
  2. Reflection中的Method是重量级的,MethodHandle对象是轻量级的,Reflection中包含了方法的签名、描述符以及方法属性表中各种属性、执行权限等,而MethodHandle仅仅包含与执行该方法相关的信息
  3. MethodHandle是字符码的方法指令调用模拟,理论上可以模拟出和JVM上一样的优化如方法内联,但是Reflection去调用方法则不可以
  4. Reflection API的设计目标是为Java语言服务的,而MethodHandle设计成可服务于所有Java虚拟机之上的语言

写在最后

MethodHandles.lookup中的findStatic()findVirtual()findSpecia()三个谅正是为了对应invokestaticinvokevirtual&invokeinterface、invokespecial这几条字节码指令的执行权限校验行为,本文中只讲到了findVirtual()方法,其它两个方法读者可以自行尝试一下。

java.lang.invoke包中的内容可以看一看,别有一番有洞天

BK wechat
扫一扫,用手机访问本站
---------------- 本文结束 ----------------