MethodHandles侧重于调用某个方法的本身, 提供了一种更高效和更底层的方法调用机制; 它和传统的反射是互补的, 合理搭配使用能使代码更加灵活高效
调用方法的例子:
一个私有方法和一个公共方法和一个私有属性
package com.example.temp.methods;
public class MethodsOne {
private String name;
private boolean compare1(String a, String b) {
return a.equals(b);
}
public boolean compare2(int a, int b) {
return a > b;
}
}
在Test里使用MethodHandles分别调用以上两个方法和对私有属性的设值与获取
package com.example.temp;
import com.example.temp.methods.MethodsOne;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.lang.invoke.*;
import java.util.*;
@SpringBootTest
class TempApplicationTests {
@Test
void invokePrivateMethod() throws Throwable {
//用来获取访问private或protected方法的Lookup对象
//也可以访问public方法(不推荐), 但需要额外的权限检查开销, 同时也会让代码意图不清晰,暗示需要特殊权限
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(MethodsOne.class, MethodHandles.lookup());
//findVirtual可用于查找实例方法(public | protected | private)
MethodHandle virtual = lookup.findVirtual(
//目标类
MethodsOne.class,
//方法名字
"compare1",
//方法签名: 返回值类型, 参数1类型, 参数2类型
MethodType.methodType(boolean.class, String.class, String.class)
).bindTo(new MethodsOne());//绑定方法所在的实例
boolean result = (boolean)virtual.invokeExact("a", "a");//调用和入参
System.out.println(result); //true
}
@Test
void invokePublicMethod() throws Throwable {
//用来获取访问public方法的Lookup对象
MethodHandles.Lookup lookup = MethodHandles.lookup();
//findVirtual可用于查找实例方法(public | protected | private)
MethodHandle virtual = lookup.findVirtual(
//目标类
MethodsOne.class,
//方法名字
"compare2",
//方法签名: 返回值类型, 参数1类型, 参数2类型
MethodType.methodType(boolean.class, int.class, int.class)
).bindTo(new MethodsOne());//绑定方法所在的实例
boolean result = (boolean) virtual.invokeExact(20, 10);//调用和入参
System.out.println(result); //true
}
@Test
void nameFieldSetterAndGetter() throws Throwable {
MethodsOne methodsOne= new MethodsOne();
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(MethodsOne.class, MethodHandles.lookup());
MethodHandle set = lookup.findSetter(
MethodsOne.class,
"name",
String.class
).bindTo(methodsOne);
set.invoke("a");//设置name的值为a
MethodHandle get = lookup.findGetter(
MethodsOne.class,
"name",
String.class
).bindTo(methodsOne);
String value = (String) get.invoke();
System.out.println(value);//a
}
}
==============================================================================
Function简单使用
package com.example.temp.methods;
import java.util.function.Function;
public class MethodTwo {
private String scoreScope(int score, Function<Integer, String> function) {
return function.apply(score);
}
}
package com.example.temp;
import com.example.temp.methods.MethodTwo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.lang.invoke.*;
import java.util.*;
import java.util.function.Function;
@SpringBootTest
class TempApplicationTests {
@Test
void funcationCase() throws Throwable {
Function<Integer, String> compare = x -> x >= 90 ? "A" : (x >= 80) ? "B" : (x >= 70) ? "C" : (x >= 60) ? "D" : "E";
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(MethodTwo.class, MethodHandles.lookup());
MethodHandle virtual = lookup.findVirtual(
MethodTwo.class,
"scoreScope",
MethodType.methodType(String.class, int.class, Function.class)
).bindTo(new MethodTwo());
String result = (String)virtual.invokeExact(75, compare);
System.out.println(result);//c
}
}