java泛型資訊儲存在哪裡
阿新 • • 發佈:2022-03-14
Java泛型確實通過型別擦除來實現,所以位元組碼中沒有型別資訊。
例如,讓我們看看兩個宣告List
欄位的類,一個是泛型的,另一個是非泛型的:
class NonGeneric {
List list;
}
和,
class Generic {
List<String> list;
}
在這兩種情況下,生成的位元組碼如下所示:
Code:
Stack=3, Locals=1, Args_size=1
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: new #2; //class java/util/ArrayList
8: dup
9: invokespecial #3; //Method java/util/ArrayList."<init>":()V
12: putfield #4; //Field list:Ljava/util/List;
15: return
沒有提及String
在ArrayList
nor中使用的型別List
。所以,我們可以看到泛型確實是通過型別擦除來實現的。
但是,如果我們看一下常量池,我們可以找到一個區別。
非泛型常量池:
Constant pool:
const #1 = Method #6.#15; // java/lang/Object."<init>":()V
const #2 = class #16; // java/util/ArrayList
const #3 = Method #2.#15; // java/util/ArrayList."<init>":()V
const #4 = Field #5.#17; // NonGeneric.list:Ljava/util/List;
const #5 = class #18; // NonGeneric
const #6 = class #19; // java/lang/Object
const #7 = Asciz list;
const #8 = Asciz Ljava/util/List;;
const #9 = Asciz <init>;
const #10 = Asciz ()V;
// snip the rest //
通用常量池:
Constant pool:
const #1 = Method #6.#17; // java/lang/Object."<init>":()V
const #2 = class #18; // java/util/ArrayList
const #3 = Method #2.#17; // java/util/ArrayList."<init>":()V
const #4 = Field #5.#19; // Generic.list:Ljava/util/List;
const #5 = class #20; // Generic
const #6 = class #21; // java/lang/Object
const #7 = Asciz list;
const #8 = Asciz Ljava/util/List;;
const #9 = Asciz Signature;
const #10 = Asciz Ljava/util/List<Ljava/lang/String;>;;
const #11 = Asciz <init>;
const #12 = Asciz ()V;
// snip the rest//
可以看出,在Generic
該類中,我們可以看到有兩個額外的常量,#9
並且#10
在常量池中提到了List
具有泛型型別String
。
(並結合我從Chris Jester-Young的回答中學到的新知識)
在類檔案的拆卸展望更遠的,還有前右為恆定#10參考Code: block
的的Generic
類:
java.util.List list;
Signature: length = 0x2
00 0A
十六進位制值0A
是10
十進位制的,它是指常量池#10
:
const #10 = Asciz Ljava/util/List<Ljava/lang/String;>;;
因此,來自常量池的資訊用於表示一個欄位是一個通用型別。