首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >装逼利器,看完这篇,让只懂反射的同学仰视你

装逼利器,看完这篇,让只懂反射的同学仰视你

作者头像
纯洁的微笑
发布于 2021-07-01 09:54:58
发布于 2021-07-01 09:54:58
51600
代码可运行
举报
文章被收录于专栏:纯洁的微笑纯洁的微笑
运行总次数:0
代码可运行

大家好,我是指北君。

昨天我朋友小 B ,在公司写 if else 被鄙视了,咱今天就来学一个装 x 利器。

反射(Reflect)作为Java最重要的一种机制,相信大家一定都很熟悉了,今天指北君要介绍另一种和反射机制类似的方法调用机制——MethodHandle。

MethodHandle是Java7引入的一种机制,主要是为了JVM支持动态语言。

一个MethodHandle调用示例

首先,让指北君给大家演示一下最基本的MethodHandle使用。

第一步:创建查找对象:Lookup
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  // 获取Look用于查找方法句柄
  MethodHandles.Lookup lookup = MethodHandles.lookup();
第二步:创建方法类型:MethodType

构造方法的返回值类型,参数类型

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  // 方法类型,描述返回值和参数,第一个参数为返回值类型,void则为void.class。第二个参数开始为被调用方法的参数类型
  MethodType mt = MethodType.methodType(boolean.class, String.class, int.class);
第三步:查找方法句柄

Lookup的findVirtual查找成员方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  //查找方法句柄,参数1:调用类,参数2:方法名,参数3:方法类型
  MethodHandle handle = lookup.findVirtual(String.class, "startsWith", mt);
第四步:方法调用

通过MehodHandle的invoke方法执行,并返回结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  //方法调用,参数1:实例,参数2..n:方法参数
  Boolean value = (Boolean)handle.invoke("the i am in the room", "the", 0);

以上就是一个简单的调用示例。

核心代码解读

上面我们展示了一个最进本MethodHandle方式的方法调用,下面我们将对其中用到的主要类进行介绍。这些主要的类包含MethodType,MethodHandle,MethodHandles及Lookup。

MethodType

首先,我们来看看Methodtype,MethodType是用来封装方法输入输出类型的,包含方法的返回和方法的参数。MethodType构造方法为私有,只能通过MethodType提供的静态工具方法来获取实例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    /**
     * 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中常用的工具方法有:

  • 大于一个参数
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    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);
    }
  • 无参数
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public static MethodType methodType(Class<?> rtype) {
        return makeImpl(rtype, NO_PTYPES, true);
    }

工具方法都通过makeImple方法来封装MethodType实例,指北君带领大家来看看makeImple中做了哪些事情:

  1. 参数检查
    • 返回值的类型不能为null,如果无返回使用void.class
    • 参数类型不能为null,且不能为void.class
  2. 使用缓存表缓存MethodType实例,优化处理
  3. 如果非信任模式(trusted==false),则克隆参数数组

这里需要注意MethodType重写了hashCode方法,从逻辑看参数数组克隆不影响同类型的缓存机制。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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的机制实现,对于使用功能来说指北君就不在此展开了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @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()方法的类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @CallerSensitive
    @ForceInline // to ensure Reflection.getCallerClass optimization
    public static Lookup lookup() {
        return new Lookup(Reflection.getCallerClass());
    }
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public static Lookup publicLookup() {
        return Lookup.PUBLIC_LOOKUP;
    }

Lookup构造方法主要传入两个参数:

  1. lookupClass搜寻的类,
  2. allowedModes:许可模式。

最后,通过Lookup的findXXX获取到MethodHandle,详细说明见下表:

查找方法

小结

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

最后感谢各位小伙伴的点赞、收藏和评论,我们下期更精彩。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 纯洁的微笑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
MethodHandle方法句柄使用分享
JDK1.7为间接调用方法提供了MethodHandle类,即方法句柄。是对之前JDK1.7之前反射性能不佳的优化手段之一 代码案例如下
每周聚焦
2024/09/18
1070
MethodHandle方法句柄使用分享
JDK1.8下关于MethodHandle问题
最近在读《深入理解java虚拟机》第二版,在JDK1.8环境下遇到一个关于MethodHandle使用上的问题,在这里记录下。https://github.com/floor07/essential-jvm (github jvm的读书笔记) 本文目录如下: 引子 java.lang.invoke简介 关于引子书上的解法 JDK1.8为什么跟预想的不一致 引子 在《深入理解java虚拟机》第二版第8章,上提出了一个问题,简要描述如下: 在Son类中,调用GrandFather的thinking方法,打印
温安适
2018/05/17
1.5K0
《深入理解Java虚拟机》读书笔记(七)–虚拟机字节码执行引擎(下)
动态类型语言的关键特征是它的类型检查的主体过程是在运行期而不是编译期,满足这个特征的语言有很多,比如JavaScript、Python等,相对的,在编译期就进行类型检查的语言(如C++/Java等)就是最常用的静态类型语言。
Java架构师必看
2021/11/29
3190
更高效的反射调用方式被我找到了!
在使用Java进行开发时,我们会不可避免的使用到大量的反射操作,比如Spring Boot会在接收到HTTP请求时,利用反射Controller调用接口中的对应方法,或是Jackson框架使用反射来解析json中的数据给对应字段进行赋值,我们可以编写一个简单的JMH测试来评估一下通过反射调用来创建对象的性能,与直接调用对象构造方法之间的差距:
程序员波特
2024/03/21
3740
报告,书里有个BUG!
是这样的,我在看《深入理解 JVM 虚拟机》(第三版)的时候发现一个有意思的 BUG。
why技术
2021/09/02
3860
关于使用MethodHandle在子类中调用祖父类重写方法的探究
这里直接看Son类的thinking方法(关于为何这样实现,在《深入理解Java虚拟机》读书笔记(七)--虚拟机字节码执行引擎(下)中也解释了)。
Java架构师必看
2021/11/29
10.2K0
Java 虚拟机:JVM是怎么实现invokedynamic的?(上)
这一天,先进分子牵着一头鹿进来,说要参加赛马。咱部里的老学究 Java 就不同意了呀,鹿又不是马,哪能参加赛马。
码农架构
2021/02/14
1.1K1
Java 虚拟机:JVM是怎么实现invokedynamic的?(上)
同事:Lambda都不懂,还写什么Java
今天的这篇文章比较长,也比较干货,刚接触指令的读者读起来可能会有点晦涩难懂,但是希望每一位读者能够沉下心来仔细阅读这篇文章,当你完全读懂这篇文章的时候,相信你对指令和Lambda的理解会更上一层楼。
shysh95
2021/02/25
4560
同事:Lambda都不懂,还写什么Java
是时候在 Java 中使用方法句柄和变量句柄了,它的效果比反射要好
反射一直是 Java 高级中不可或缺的一部分。如今,它正被更新、更安全的方式所取代。本文将介绍如何使用方法句柄(MethodHandle)和变量句柄(VarHandle)以编程方式访问方法和字段。
前端修罗场
2024/12/22
2460
反射太慢?那是你不会用LambdaMetafactory!
在之前的文章中,我们介绍使用Spring工具类ReflectionUtils通过缓存、避免创建临时对象的方式来优化反射的性能
菜菜的后端私房菜
2024/12/25
3650
理解 JDK 中的 MethodHandle
该文介绍了Java编程语言中MethodHandle和Method的区别,以及它们的用途和性能差异。MethodHandle在JDK 8及之前主要作为Method的代理对象,在JDK 9之后,MethodHandle被设计为与Method独立存在,有自己的语义和语义解析。MethodHandle在运行时可以通过JVM的代理机制进行调用,而Method需要先获取到对象后才能调用。此外,MethodHandle的调用比Method的调用性能更高,因为MethodHandle的调用不需要获取对象,而Method的调用需要先获取对象。
serena
2017/09/14
5.4K0
MethodHandle结合LambdaMetafactory-使用方法及性能测试
在进行实例的动态推断和构建时,我们会经常使用到反射这一技巧,然而在某些场景中反射的效率显得有些力不从心。从JDK7开始,MethodHandle被推出,用于解决反射的效率问题。在JDK8,MethodHandle又与Lambda进行深度结合,成为Lambda的最底层调用方式。在JDK9,MethodHandle又被进一步增强。 在开源项目中,Mybatis Mapper的动态代理实现则运用了MethodHandle。
benym
2023/02/14
2.2K0
Java 虚拟机:JVM是怎么实现invokedynamic的?(下)
上回讲到,为了让所有的动物都能参加赛马,Java 7 引入了 invokedynamic 机制,允许调用任意类的“赛跑”方法。不过,我们并没有讲解 invokedynamic,而是深入地探讨了它所依赖的方法句柄。
码农架构
2021/02/14
2.2K1
Java 虚拟机:JVM是怎么实现invokedynamic的?(下)
深入探究JVM之方法调用及Lambda表达式实现原理
在最开始讲解JVM内存结构的时候有简单分析过方法的执行原理——每一次方法调用都会生成一个栈帧并压入栈中,方法链的执行就是一个个栈帧弹出栈的过程,本篇就从字节码层面详细分析方法的调用细节。
夜勿语
2020/09/07
7590
方法引用(Method reference)和invokedynamic指令详细分析
invokedynamic是jvm指令集里面最复杂的一条。本文将详细分析invokedynamic指令是如何实现方法引用(Method reference)的。
racaljk
2019/02/25
9410
嗨,朋友,你还在用Java 8 吗?Java 23 正式发布了~
9月19日消息,Java 23目前已经正式推出,这是继Java 22之后的又一个非长期支持(LTS)版本,Oracle 对此版本仅提供六个月的支持。 Java 23包含12个新的JEP(JDK增强提案),其中包括其中包括将ZGC的默认模式切换为分代模式。
不惑
2024/09/24
1K0
嗨,朋友,你还在用Java 8 吗?Java 23 正式发布了~
JDK11中增加了一个常量池类型:CONSTANT_Dynamic
有关class file 的内容,这里不再赘述。你可以参阅此文:来自JVM的一封ClassFile介绍信。
ImportSource
2018/07/25
1.7K0
JDK11中增加了一个常量池类型:CONSTANT_Dynamic
揭密 Java方法调用的底层原理
我们在日常开发中,其实很少去关注字节码层面的东西。但,作为我们的吃饭家伙,个人觉得还是很有必要了解的。
田维常
2021/10/27
1.6K0
揭密 Java方法调用的底层原理
深入理解Java中的反射机制和使用原理!详细解析invoke方法的执行和使用
newInstance方法可以根据传入的参数来调用对应的Constructor创建对象的实例
攻城狮Chova
2022/02/24
2.1K0
深入理解Java中的反射机制和使用原理!详细解析invoke方法的执行和使用
Java Concurrent Atomic实现原理&源码解读(JDK 10)
JDK 10,可以说是很新了,比起JDK 8更新了不少实现,比如说下面会讲到VarHandle
邹志全
2019/07/31
8200
推荐阅读
相关推荐
MethodHandle方法句柄使用分享
更多 >
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档