繁体   English   中英

如何在另一个生成字节码类中使用匿名类实例

[英]How to use an anonymous class instance in another generate bytecode class

我在使用由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的构造函数?

看一下签名和文档注释 ,由于它不是官方API的一部分,因此在标准API文档中不可用:

定义一个类,但不要让类加载器或系统字典知道它。 对于每个CP条目,相应的CP修补程序必须为null或具有与其标签匹配的格式:

  • Integer,Long,Float,Double:java.lang中对应的包装器对象类型
  • utf8:字符串(如果用作签名或名称,则必须具有适当的语法)类:任何java.lang.Class对象
  • 字符串:任何对象(不只是java.lang.String)
  • InterfaceMethodRef:(NYI)在该调用站点的参数上调用的方法句柄

…(参数:)

存在非空条目的cpPatches ,它们替换数据中相应的CP条目

 public native Class<?> defineAnonymousClass( Class<?> hostClass, byte[] data, Object[] cpPatches); 

换句话说,您可以提供与要定义的类的常量池相同大小的数组。 null保留在您不想对其进行修改的位置。 在常量池中具有代表匿名类的CONSTANT_Class_info的位置上,您只需在数组中传递关联的Class对象。 因此,无需查找该类,您甚至不必在类字节中提供正确的类名称。

有一些明显的局限性:

  • 如果您具有循环依赖关系,则会出现问题,因为您需要一个已经存在的Class对象来修补另一个类的池。 好吧,对于已知可以延迟解决的类使用,它可能会起作用
  • 你只能修补CONSTANT_Class_infoClass是足够的,例如访问该类的成员或创建该包的新实例。 但是,当匿名类是签名的一部分时,即当您要声明该类型的字段或使用将其作为参数或返回类型的方法时,这无济于事。 但是您可以使用通过MethodHandle修补CONSTANT_InterfaceMethodref_info条目的选项来访问此类方法( MethodHandle ,一旦实现,我猜“ NYI”就意味着“尚未实现”)…

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM