import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
/**
* 动态语言API测试
*/
public class DynamicTest {
private static void test(){
System.out.println("动态语言API测试");
}
public static void main(String[] args) throws Throwable {
// public方法的Lookup
// MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
// 所有方法的Lookup
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findStatic(DynamicTest.class,"test", MethodType.methodType(void.class));
mh.invokeExact();
}
}
动态语言API测试
methodhandler相较于反射更轻量级:
1.本质上讲两个都是在模拟方法的调用,但Reflection是模拟java代码层次的调用,而MethodHandle是模拟的字节码层次的,上面的例子中是模拟的invokevirtual指令。
2.Reflection是重量级的,而MethodHandle是轻量级的。
最重要的是,Reflection 只为java服务,而MethodHandle则可以服务于所有的运行在java虚拟机上的语言。
public class MethodHandlerTest {
static class A {
public void println(String s) {
System.err.println("i am class A:" + s);
}
}
public static void main(String[] args) throws Throwable {
Object object = System.currentTimeMillis() % 2 == 0 ? System.out : new A();
//无论 object是要那个实现类,下面的都能正确调用 到println方法
getPrintlnMh(object).invokeExact("lisj");
}
private static MethodHandle getPrintlnMh(Object target) throws Exception {
MethodType methodType = MethodType.methodType(void.class, String.class);
return MethodHandles.lookup().findVirtual(target.getClass(), "println", methodType).bindTo(target);
}
}
https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.4.4
表4.4-B。常量池标签(按标签)
| 常数种类 | 标签 | class 文件格式 | Java SE |
|---|---|---|---|
CONSTANT_Utf8 | 1 | 45.3 | 1.0.2 |
CONSTANT_Integer | 3 | 45.3 | 1.0.2 |
CONSTANT_Float | 4 | 45.3 | 1.0.2 |
CONSTANT_Long | 五 | 45.3 | 1.0.2 |
CONSTANT_Double | 6 | 45.3 | 1.0.2 |
CONSTANT_Class | 7 | 45.3 | 1.0.2 |
CONSTANT_String | 8 | 45.3 | 1.0.2 |
CONSTANT_Fieldref | 9 | 45.3 | 1.0.2 |
CONSTANT_Methodref | 10 | 45.3 | 1.0.2 |
CONSTANT_InterfaceMethodref | 11 | 45.3 | 1.0.2 |
CONSTANT_NameAndType | 12 | 45.3 | 1.0.2 |
CONSTANT_MethodHandle | 15 | 51.0 | 7 |
CONSTANT_MethodType | 16 | 51.0 | 7 |
CONSTANT_Dynamic | 17 | 55.0 | 11 |
CONSTANT_InvokeDynamic | 18 | 51.0 | 7 |
CONSTANT_Module | 19 | 53.0 | 9 |
CONSTANT_Package | 20 | 53.0 | 9 |
表中的某些条目constant_pool是可加载的, 因为它们表示可以在运行时压入堆栈以实现进一步计算的实体。在class版本号为v的文件中,constant_pool如果表中的条目具有首先被认为可在文件格式v或更早版本中加载的标记,则该表中的条目是可加载的class。 表4.4-C列出了每个标签,class其中包含可被加载的文件格式的第一个版本。还显示了Java SE平台的版本,该版本引入了该版本的class文件格式。
在除了之外的每种情况下CONSTANT_Class,首先认为标签可以在class首先定义标签的相同版本的文件格式中加载。
表4.4-C。可加载的常量池标记
| 常数种类 | 标签 | class 文件格式 | Java SE |
|---|---|---|---|
CONSTANT_Integer | 3 | 45.3 | 1.0.2 |
CONSTANT_Float | 4 | 45.3 | 1.0.2 |
CONSTANT_Long | 五 | 45.3 | 1.0.2 |
CONSTANT_Double | 6 | 45.3 | 1.0.2 |
CONSTANT_Class | 7 | 49.0 | 5 |
CONSTANT_String | 8 | 45.3 | 1.0.2 |
CONSTANT_MethodHandle | 15 | 51.0 | 7 |
CONSTANT_MethodType | 16 | 51.0 | 7 |
CONSTANT_Dynamic | 17 | 55.0 | 11 |