2009-06-02 55 views

回答

29

它們存儲在Signature屬性中;請參閱updated Java Virtual Machine Specification的第4.8.8節和字段類型簽名格式的第4.4.4節。

下面是一個使用javap -verbose java.util.Map一個例子:

public interface java.util.Map 
    SourceFile: "Map.java" 
    Signature: length = 0x2 
    00 1E 
    [other attributes omitted] 

Signature屬性在這裏指定(如果你看這是大端,就像在JVM類文件格式的所有整數數量是)常量池值#30( 30 = 0x1E)。所以讓我們看看那裏:

const #30 = Asciz  <K:Ljava/lang/Object;V:Ljava/lang/Object;>Ljava/lang/Object;; 

在4.4.4中指定的語法的上下文中閱讀此內容。所以,這使用了兩個類型參數,K extends java.lang.ObjectV extends java.lang.Object。類型本身(Map)也延伸類java.lang.Object,並且沒有接口。

14

Java泛型確實由type erasure實現,所以在字節碼中沒有類型信息。

例如,讓我們來看看它聲明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 

沒有引用在ArrayListList中使用的String類型。所以,我們可以看到泛型確實是通過類型擦除來實現的。

但是,如果我們看一下常量池,我們可以找到差異。

非通用常量池:

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's answer教訓)

在類文件的拆卸展望更遠的,有Generic類的Code: block前權恆#10參考:

java.util.List list; 
    Signature: length = 0x2 
    00 0A 

十六進制值0A是十進制10,它指的是常量池#10

const #10 = Asciz Ljava/util/List<Ljava/lang/String;>;; 

因此,來自常量池的信息用於表示字段是泛型類型。