【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 ...
随机推荐
- 谷粒 | 11 | nginx windows版简单安装使用
nginx配置 下载安装 传送门:官网下载 官网提供三种版本: Mainline version:Mainline 是 Nginx 目前主力在做的版本,可以说是开发版 Stable version:最 ...
- 关于React采坑(憨批)系列---类组件(class MyCom extends React.Component--VM47:9 Uncaught TypeError: Super expression must either be null or a function, not undefined)
今天在学习React中的类组件时,突然给我报错VM47:9 Uncaught TypeError: Super expression must either be null or a function ...
- Linux Mem (目录)
1.用户态相关: 1.1.用户态进程空间的创建 - execve() 详解 1.2.用户态进程空间的映射 - mmap()详解 1.3.分页寻址(Paging/MMU)机制详解 2.内核态相关: 2. ...
- java中的lamda表达式
List操作: 循环: list.forEach((p) -> System.out.printf("%s %s; %n", p.getFirstName(), p.getL ...
- c++学习笔记目录
chapter name menu 一 从c到c++ 1.引用2.const关键词的用法3.动态内存分配4.内联函数5.函数重载6.函数的缺省参数7.结构化程序设计的不足8.面向对象的程序设计 二 类 ...
- OpenShift S2I 概念及流程
S2I 概念 S2I(Source To Image)即从源码到镜像的一个过程,OpenShift 将它作为基础功能提供给用户,包含 S2I CLI 工具 与 S2I 流程.通过这些工具和既定流程,能 ...
- 题解 P6345 [CCO 2017]接雨滴
解题思路 NOIP在即,感觉即将退役,或许是最后一篇题解了... 求水的体积不是特别好求,我们考虑求出 水+柱子 的体积最后再减去柱子的体积. 发现对于最高的柱子在中间的情况其实可以把最高柱子一侧的柱 ...
- JAVA基础----面向对象复习和IDEA的安装和使用
1.使用集成开发工具eclipse 1.1.java的集成开发工具很多,包括:eclipse.Intellij IDEA.netbeans..... eclipse: IBM开发的.eclipse翻译 ...
- JavaScript Sanitizer API:原生WEB安全API出现啦
10月18号, W3C中网络平台孵化器小组(Web Platform Incubator Community Group)公布了HTML Sanitizer API的规范草案.这份草案用来解决浏览器如 ...
- Codeforces 590E - Birthday(AC 自动机+Dilworth 定理+二分图匹配)
题面传送门 AC 自动机有时只是辅助建图的工具,真的 首先看到多串问题,果断建出 AC 自动机.设 \(m=\sum|s_i|\). 不难发现子串的包含关系构成了一个偏序集,于是我们考虑转化为图论,若 ...