簡體   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