【Java基础】方法调用机制——MethodHandle
MethodHandle是Java7引入的一种机制,主要是为了JVM支持动态语言。
一个MethodHandle调用示例
共有方法调用
首先,演示一下最基本的MethodHandle使用。
第一步:创建查找对象:Lookup
// 获取Look用于查找方法句柄
MethodHandles.Lookup lookup = MethodHandles.lookup();
第二步:创建方法类型:MethodType
构造方法的返回值类型,参数类型
// 方法类型,描述返回值和参数,第一个参数为返回值类型,void则为void.class。第二个参数开始为被调用方法的参数类型
MethodType mt = MethodType.methodType(boolean.class, String.class, int.class);
第三步:查找方法句柄
Lookup的findVirtual查找成员方法
//查找方法句柄,参数1:调用类,参数2:方法名,参数3:方法类型
MethodHandle handle = lookup.findVirtual(String.class, "startsWith", mt);
第四步:方法调用
通过MehodHandle的invoke方法执行,并返回结果
//方法调用,参数1:实例,参数2..n:方法参数
Boolean value = (Boolean)handle.invoke("the i am in the room", "the", 0);
私有方法调用
public static void main(String..) {
Lookup myLookup = MethodHandles.lookup();
UserFactory foo = new UserFactory(); // test
User baz = new User();
try {
Method m = UserFactory.class.getDeclaredMethod("cnu", User.class);
m.setAccessible(true);
MethodHandle pmh = myLookup.unreflect(m);
boolean b = (boolean)pmh.invoke(foo, baz);
} catch (Exception e) {
e.printStackTrace();
} catch (Throwable e) {
e.printStackTrace();
}
}
以上就是一个简单的调用示例。
核心代码解读
上面我们展示了一个最进本MethodHandle方式的方法调用,下面我们将对其中用到的主要类进行介绍。这些主要的类包含MethodType,MethodHandle,MethodHandles及Lookup。
MethodType
首先,我们来看看Methodtype,MethodType是用来封装方法输入输出类型的,包含方法的返回和方法的参数。MethodType构造方法为私有,只能通过MethodType提供的静态工具方法来获取实例
/**
* Constructor that performs no copying or validation.
* Should only be called from the factory method makeImpl
*/
private MethodType(Class<?> rtype, Class<?>[] ptypes) {
this.rtype = rtype;
this.ptypes = ptypes;
}
MethodType中常用的工具方法有:
- 大于一个参数
public static MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
ptypes1[0] = ptype0;
System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
return makeImpl(rtype, ptypes1, true);
}
- 无参数
public static MethodType methodType(Class<?> rtype) {
return makeImpl(rtype, NO_PTYPES, true);
}
工具方法都通过makeImple方法来封装MethodType实例,指北君带领大家来看看makeImple中做了哪些事情:
参数检查
- 返回值的类型不能为null,如果无返回使用void.class
- 参数类型不能为null,且不能为void.class
使用缓存表缓存MethodType实例,优化处理
如果非信任模式(trusted==false),则克隆参数数组
这里需要注意MethodType重写了hashCode方法,从逻辑看参数数组克隆不影响同类型的缓存机制。
static
MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
if (ptypes.length == 0) {
ptypes = NO_PTYPES; trusted = true;
}
MethodType primordialMT = new MethodType(rtype, ptypes);
MethodType mt = internTable.get(primordialMT);
if (mt != null)
return mt;
// promote the object to the Real Thing, and reprobe
MethodType.checkRtype(rtype);
if (trusted) {
MethodType.checkPtypes(ptypes);
mt = primordialMT;
} else {
// Make defensive copy then validate
ptypes = Arrays.copyOf(ptypes, ptypes.length);
MethodType.checkPtypes(ptypes);
mt = new MethodType(rtype, ptypes);
}
mt.form = MethodTypeForm.findForm(mt);
return internTable.add(mt);
}
除了静态工具方法外,MethodType还有几个实例方法,主要为差异性较小的MethodType提供快速获取实例的方法。包含:
- changeParameterType
- insertParameterTypes
- appendParameterTypes
- dropParameterTypes
MethodHandle
MethodHandle为抽象类,但是里面提供了大量的原生方法,提供底层访问,也是方法调用的核心逻辑。这部分涉及MethodHandle的机制实现,对于使用功能来说就不在此展开了。
@HotSpotIntrinsicCandidate
public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable;
@HotSpotIntrinsicCandidate
public final native @PolymorphicSignature Object invoke(Object... args) throws Throwable;

MethodHandles, Lookup
MethodHandles不是MethodHandle的实现,他提供工具用于帮助获取MethodHandle,我们主要使用到lookup(),publicLookup()
@CallerSensitive注解,可以使Reflection.getCallerClass()获取到调用lookup()方法的类
@CallerSensitive
@ForceInline // to ensure Reflection.getCallerClass optimization
public static Lookup lookup() {
return new Lookup(Reflection.getCallerClass());
}
public static Lookup publicLookup() {
return Lookup.PUBLIC_LOOKUP;
}
Lookup构造方法主要传入两个参数:
- lookupClass搜寻的类,
- allowedModes:许可模式。
最后,通过Lookup的findXXX获取到MethodHandle,详细说明见下表:

小结
关于MethodHandle的基本使用就基本讲完,这里附上一张类图便大家理解:

【Java基础】方法调用机制——MethodHandle的更多相关文章
- Java方法调用机制
最近在编程时,修改方法传入对象的对象引用,并没有将修改反映到调用方法中.奇怪为什么结果没有变化,原因是遗忘了Java对象引用和内存分配机制.本文介绍3个点: ① 该问题举例说明 ② 简要阐述Java内 ...
- Java基础——方法的调用
Java基础--方法的调用 总结: 1. 在同一个类中-- 对于静态方法,其他的静态和非静态方法都可以直接通过"方法名"或者"类名.方法名"调用它. 对 ...
- 《Java基础——方法的调用》
Java基础--方法的调用 总结: 1. 在同一个类中-- 对于静态方法,其它的静态和非静态方法都可以直接通过"方法名"或者"类名.方法名"调用它. 对 ...
- Java基础-方法(method)的应用
Java基础-方法(method)的应用 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 方法就是定义在类中,具有特定功能的一段小程序,方法也称为函数(function),方法可以接 ...
- [转]Java远程方法调用
Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口.它使客户机上运行的程序可以调用远 ...
- java基础:方法的定义和调用详细介绍,方法同时获取数组最大值和最小值,比较两个数组,数组交换最大最小值,附练习案列
1. 方法概述 1.1 方法的概念 方法(method)是将具有独立功能的代码块组织成为一个整体,使其具有特殊功能的代码集 注意: 方法必须先创建才可以使用,该过程成为方法定义 方法创建后并不是直接可 ...
- Java基础:类加载机制
之前的<java基础:内存模型>当中,我们大体了解了在java当中,不同类型的信息,都存放于java当中哪个部位当中,那么有了对于堆.栈.方法区.的基本理解以后,今天我们来好好剖析一下,j ...
- java基础之反射机制
一.概念 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为jav ...
- java中方法调用
JAVA中方法的调用[基础] 一.调用本类中的方法 方法一.被调用方法声明为static ,可以在其他方法中直接调用.示例代码如下: public class HelloWord { /** * @p ...
随机推荐
- 解决一次gitlab因异常关机导致启动失败
解决一次gitlab因异常关机导致启动失败 目录 解决一次gitlab因异常关机导致启动失败 1. 服务器异常关机 2. gitlab服务 2.1 进入gitlab容器内部 2.2 检查gitlab各 ...
- 2021 羊城杯WriteUP
比赛感受 题目质量挺不错的,不知道题目会不会上buu有机会复现一下,躺了个三等奖,发下队伍的wp Team BinX from GZHU web Checkin_Go 源码下载下来发现是go语言写的 ...
- 力扣 - 剑指 Offer 12. 矩阵中的路径
题目 剑指 Offer 12. 矩阵中的路径 思路1(回溯.DFS) 这题可以使用回溯+递归来解决,思路如下: 将二维数组的每一个元素都作为起点进行回溯查找 每次查找的时候,都有四个方向,但是上一个方 ...
- [bzoj1576]安全路径
先建立最短路径树(即跑dij每一个点向更新他的点连边),考虑一个点的答案路径一定要走过且仅走过一条非树边,枚举非树边(x,y),对于一个点k,如果它在x~lca上(y~lca的路径上同理),那么答案可 ...
- C/C++ Qt TableDelegate 自定义代理组件
TableDelegate 自定义代理组件的主要作用是对原有表格进行调整,例如默认情况下Table中的缺省代理就是一个编辑框,我们只能够在编辑框内输入数据,而有时我们想选择数据而不是输入,此时就需要重 ...
- Codeforces 375C - Circling Round Treasures(状压 dp+最短路转移)
题面传送门 注意到这题中宝藏 \(+\) 炸弹个数最多只有 \(8\) 个,故考虑状压,设 \(dp[x][y][S]\) 表示当前坐标为 \((x,y)\),有且仅有 \(S\) 当中的物品被包围在 ...
- 洛谷 P4484 - [BJWC2018]最长上升子序列(状压 dp+打表)
洛谷题面传送门 首先看到 LIS 我们可以想到它的 \(\infty\) 种求法(bushi),但是对于此题而言,既然题目出这样一个数据范围,硬要暴搜过去也不太现实,因此我们需想到用某种奇奇怪怪的方式 ...
- Codeforces 1089I - Interval-Free Permutations(析合树计数)
Codeforces 题面传送门 & 洛谷题面传送门 首先题目中涉及排列的 interval,因此可以想到析合树.由于本蒟蒻太菜了以至于没有听过这种神仙黑科技,因此简单介绍一下这种数据结构:我 ...
- R语言与医学统计图形-【30】流行病学数据可视化
sjPlot包适用于社会科学.流行病学中调查数据可视化,且能和SPSS数据无缝对接(流行病学问卷调查录入Epidata软件后,都会转成SPSS格式或EXCEL格式保存). 辅助包sjmisc进行数据转 ...
- micropython1.16官方文档转PDF
折腾了一天,终于把micropython1.16的官方文档给转成了pdf格式. 不过转换成PDF格式以后存在两点问题: 1.PDF文档有些地方的排版中有些行距没有调整好: 2.使用latex编译tex ...