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);
}
}