java7新特性之方法句柄MethodHandle使用

简介: java7新特性之方法句柄MethodHandle使用

场景

今天看jvm虚拟机初始化的阶段时候,发现有下面5种情况,会触发初始化

初始化阶段,虚拟机规范则是严格规定了有且只有5种情况必须立即对类进行“初始化”(而加载、验证、准备自然需要在此之前开始):

1)遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令的最常见的Java代码场景是:使用new关键字实例化对象的时候、读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。

2)使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。

3)当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

4)当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。

5)当使用JDK 1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

其中第5条没接触过,饿补了一下MethodHandle的使用场景。

MethodHandle

JDK6之前我们会使用java反射来实现动态方法调用,多数框架用反射的比较多,例如mybatis、spring等。在JDK7中,新增了java.lang.invoke.MethodHandle(方法句柄),称之为“现代化反射”。其实反射和java.lang.invoke.MethodHandle都是间接调用方法的途径,但java.lang.invoke.MethodHandle比反射更简洁,用反射功能会写一大堆冗余代码

官方api给出的解释:

A method handle is a typed, directly executable reference to an underlying method, constructor, field, or similar low-level operation, with optional transformations of arguments or return values.其实就是可以获取方法的句柄,类似方法的指针。

下面看一个例子,使用方法句柄(MethodHandle)调用toString()方法:
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
/**
 * Created by hfl on 2020/12/11
 */
public class MHTestDemo {
    public String toString(String s) {
        return "hello," + s + "MethodHandle";
    }
    public static void main(String[] args) {
        MHTestDemo mhTest = new MHTestDemo();
        MethodHandle mh = getToStringMH();  //获取方法句柄
        try {
            // 1.调用方法:
            String result = (String) mh.invokeExact(mhTest, "ssssss");  //根据方法句柄调用方法----注意返回值必须强转
            System.out.println(result);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        // 2.or like this:
        try {
            MethodHandle methodHandle2 = mh.bindTo(mhTest);
            String toString2 = (String) methodHandle2.invokeWithArguments("sssss");
            System.out.println(toString2);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        // 得到当前Class的不同表示方法,最后一个最好。一般我们在静态上下文用SLF4J得到logger用。
        System.out.println(MHTestDemo.class);
        System.out.println(mhTest.getClass());
        System.out.println(MethodHandles.lookup().lookupClass()); // like getClass()
    }
    /**
     * 获取方法句柄
     * @return
     */
    public static MethodHandle getToStringMH() {
        //获取方法类型 参数为:1.返回值类型,2方法中参数类型
        MethodType mt = MethodType.methodType(String.class, String.class);
        MethodHandle mh = null;
        try {
            //查找方法句柄
            mh = MethodHandles.lookup().findVirtual(MHTestDemo.class, "toString", mt);
        } catch (NoSuchMethodException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return mh;
    }
}

运行结果:

hello,ssssssMethodHandle

hello,sssssMethodHandle

class com.gupao.gpjvm.ch01.MHTestDemo

class com.gupao.gpjvm.ch01.MHTestDemo

class com.gupao.gpjvm.ch01.MHTestDemo


本文完。

相关文章
|
6月前
|
Java
Java语言实现字母大小写转换的方法
Java提供了多种灵活的方法来处理字符串中的字母大小写转换。根据具体需求,可以选择适合的方法来实现。在大多数情况下,使用 String类或 Character类的方法已经足够。但是,在需要更复杂的逻辑或处理非常规字符集时,可以通过字符流或手动遍历字符串来实现更精细的控制。
416 18
|
6月前
|
Java 编译器 Go
【Java】(5)方法的概念、方法的调用、方法重载、构造方法的创建
Java方法是语句的集合,它们在一起执行一个功能。方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用方法的优点使程序变得更简短而清晰。有利于程序维护。可以提高程序开发的效率。提高了代码的重用性。方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerson。这种就属于驼峰写法下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。
288 4
|
6月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
387 5
|
7月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
225 11
|
7月前
|
Java API 数据处理
Java新特性:使用Stream API重构你的数据处理
Java新特性:使用Stream API重构你的数据处理
|
7月前
|
Java 开发者
Java 函数式编程全解析:静态方法引用、实例方法引用、特定类型方法引用与构造器引用实战教程
本文介绍Java 8函数式编程中的四种方法引用:静态、实例、特定类型及构造器引用,通过简洁示例演示其用法,帮助开发者提升代码可读性与简洁性。
Java API 开发者
218 0
|
8月前
|
算法 Java
Java语言实现链表反转的方法
这种反转方法不需要使用额外的存储空间,因此空间复杂度为,它只需要遍历一次链表,所以时间复杂度为,其中为链表的长度。这使得这种反转链表的方法既高效又实用。
607 0
|
6月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
295 1
|
6月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
317 1