Java学习笔记一MethodHandle和VarHandle

Java 9增强的MethodHandle

MethodHandle为Java增加了方法引用的功能,方法引用的概念有点类似于C的函数指针。这种方法引用是一种轻量级的引用方式,它不会检查方法的访问权限,也不管方法所属的类、实例方法或静态方法,MethodHandle就是简单代表特定的方法,并可通过MethodHandle来调用方法。
MethodHandles是MethodHandle的工厂类,它提供了一系列静态方法用于获取MethodHandle。MethodHandles.Lookup静态内部类也是MethodHandle、VarHandle的工厂类,专门用于获取MethodHandle和VarHandle。MethodType代表一个方法类型,根据方法的形参、返回值类型来确定方法类型。

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class MethodHandleTest {
    // 定义一个private类方法
    private static void hello(){ System.out.println("hello world!"); }
    // 定义一个private实例方法
    private String hello(String name) { System.out.println("执行带参数的hello"+name); return name+",您好"; }
    public static void main(String[] args) throws Throwable{
        // 定义一个返回值值为void、不带形参的方法类型
        MethodType type = MethodType.methodType(void.class);
        // 使用MethodHandles.Lookup的findStatic获取类方法
        MethodHandle mtd = MethodHandles.lookup().findStatic(MethodHandleTest.class, "hello", type);
        // 通过MethodHandle执行方法
        mtd.invoke();

        // 使用MethodHandles.Lookup的findVirtual获取实例方法                                            指定获取返回值为String、形参为String的方法类型
        MethodHandle mtd2 = MethodHandles.lookup().findVirtual(MethodHandleTest.class, "hello", MethodType.methodType(String.class, String.class));
        System.out.println(mtd2.invoke(new MethodHandleTest(), "孙空"));
    }
}

在这里插入图片描述

Java 9增强的VarHandle

VarHandle主要用于动态操作数组的元素或对象的成员变量。VarHandle与MethodHandle非常类似,它也需要通过MethodHandles来获取实例,接下来调用VarHandle的方法即可动态操作指定数组的元素或指定对象的成员变量。

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.Arrays;

class User{
    String name;
    static int MAX_AGE;
}
public class VarHandleTest {
    public static void main(String[] args) throws Throwable{
        String[] sa = new String[]{"Java", "Kotlin", "Go"};
        // 获取一个String[]数组的VarHandle对象
        VarHandle avh = MethodHandles.arrayElementVarHandle(String[].class);
        // 比较并设置:如果第三个元素是Go,则该元素被设置为Lua
        boolean r = avh.compareAndSet(sa, 2, "Go", "Lua");
        System.out.println(r);
        // 看到第三个元素被替换为Lua
        System.out.println(Arrays.toString(sa));
        // 获取sa数组的第二个元素
        System.out.println(avh.get(sa,1));
        // 获取并设置:返回第三个元素,并将第三个元素设置为Swift
        System.out.println(avh.getAndSet(sa, 2, "Swift"));
        // 看到第三个元素被替换成Swift
        System.out.println(Arrays.toString(sa));

        //用findVarHandle方法获取User类中名为name类型为String的实例变量
        VarHandle vh = MethodHandles.lookup().findVarHandle(User.class, "name", String.class);
        User user = new User();
        // 通过VarHandle获取实例变量的值,需要传入对象作为调用者
        System.out.println(vh.get(user)); // 输出null
        // 通过VarHandle设置指定实例变量的值
        vh.set(user, "悟空");
        // 输出user的name实例变量的值
        System.out.println(user.name);

        // 用findVarHandle方法获取User类中名为MAX_AGE类型为Integer的类变量
        VarHandle vh1 = MethodHandles.lookup().findStaticVarHandle(User.class, "MAX_AGE", int.class);
        // 通过VarHandle获取类变量的值
        System.out.println(vh1.get()); // 输出0
        // 通过VarHandle设置指定类变量的值
        vh1.set(100);
        // 输出user的MAX_AGE类变量的值
        System.out.println(User.MAX_AGE);
    }
}

在这里插入图片描述

你可能感兴趣的:(Java)