我很难使用Unsafe.defineAnonymousClass()
加载的生成的字节码类。我想知道如何使用匿名类的对象初始化另一个类(或匿名类)。
以下面的示例类Callee为例,其构造函数接受Callee2作为参数。
Class Callee{
Callee2 _call2;
public Callee(Callee2 callee2){
...
}
}
在运行时,我为Callee2和Callee生成了新类,并且这两个新类都由
Unsafe.defineAnonymousClass()
加载。对于新的Callee,构造函数也更改为: public test.code.jit.asm.simple.Callee(test.code.jit.asm.simple.Callee2.1506553666);
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=2
0: aload_0
1: invokespecial #65 // Method java/lang/Object."<init>":()V
....
8: return
而Callee2的生成类名称为:
class test.code.jit.asm.simple.Callee2/1506553666
我创建了`Callee2 / 1506553666'的实例,并想用它创建新Callee的实例,但是失败了:
newCls.getConstructor(args).newInstance(objs);
哪里
args = [class test.code.jit.asm.simple.Callee2/1506553666]
和objs= [test.code.jit.asm.simple.Callee2/1506553666@39b0a038]
args [0]毫无意义,因为此类是由匿名加载器加载的(任何类加载器均未引用匿名类)。因此,这真的使我感到困惑,如何将objs数组中的对象传递给方法调用。
使用消息调用getConstructor(args)时会发生异常:
java.lang.NoClassDefFoundError: test/code/jit/asm/simple/Callee2/1506553666
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2483)
at java.lang.Class.getConstructor0(Class.java:2793)
at java.lang.Class.getConstructor(Class.java:1708)
at code.jit.asm.util.ReflectionUtil.adapt2GeneratedObject(ReflectionUtil.java:36)
at code.jit.asm.services.BytecodeGenerator.generator(BytecodeGenerator.java:164)
对我来说显然是个例外,因为匿名类对于任何类加载器都是临时的。但就我而言,我确实需要通过新的Callee2实例初始化新的Callee(也是匿名类)(Callee的构造函数中的字节码将读取Callee2的字段成员),因此,是否有任何变通办法将新的Callee2实例传递给新的Callee2的构造函数?
最佳答案
看看the signature and documentation comment,它不是标准API的一部分,因此在标准API文档中不可用:
定义一个类,但不要让类加载器或系统字典知道它。
对于每个CP条目,相应的CP修补程序必须为null或具有与其标签匹配的格式:
类:任何java.lang.Class对象
…(参数:)
存在非空条目的
cpPatches
,它们替换数据中相应的CP条目public native Class<?> defineAnonymousClass(
Class<?> hostClass, byte[] data, Object[] cpPatches);
换句话说,您可以提供与要定义的类的常量池相同大小的数组。将
null
保留在您不想对其进行修改的位置。在常量池中有一个表示匿名类的CONSTANT_Class_info
的地方,您只需在数组中传递关联的Class
对象。这样一来,无需查找该类,您甚至不必在类字节中提供正确的类名称。有一些明显的局限性:
Class
对象来修补另一个类的池。好吧,对于已知会延迟解决的类用法,它可能会起作用CONSTANT_Class_info
修补为足以满足要求的Class
,例如访问该类的成员或创建该类的新实例。但是,当匿名类成为签名的一部分时,即您要声明该类型的字段或使用将其作为参数或返回类型的方法时,这无济于事。但是您可以使用通过CONSTANT_InterfaceMethodref_info
修补MethodHandle
条目的选项来访问此类方法(哎呀,一旦实现,因为我猜“NYI”的意思是“尚未实现”)…