2009-06-02 26 views

Odpowiedz

29

Są przechowywane w atrybutach Signature; patrz sekcja 4.8.8 z updated Java Virtual Machine Specification, a także sekcja 4.4.4 dla formatu podpisu typu pola.

Oto przykład przy użyciu javap -verbose java.util.Map:

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

Atrybut tutaj określa (jeśli czytasz to jako grubokońcej, podobnie jak wszystkie ilości całkowitą w formacie klasy JVM ARE) stała pula wartość # 30 (Signature 30 = 0x1E).Zobaczmy więc:

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

Przeczytaj to w kontekście gramatyki określonej w 4.4.4. Wykorzystuje to dwa parametry: K extends java.lang.Object i V extends java.lang.Object. Sam typ (Map) również rozszerza klasę java.lang.Object i nie zawiera żadnych interfejsów.

14

Generics Java są rzeczywiście realizowane przez type erasure, więc nie ma informacji o typie w bajtode.

Na przykład, weźmy spojrzeć dwie klasy, które deklarują List pole, jeden w generycznym, a drugi w formie non-Generic:

class NonGeneric { 
    List list; 
} 

I

class Generic { 
    List<String> list; 
} 

W obu przypadkach , wynikowy kod jest następujący:

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 

Brak informacji o typie String używanym w ArrayList ani List. Widzimy więc, że generics jest rzeczywiście realizowany przez typ wymazania.

Jednakże, jeśli spojrzymy na stałą pulę, możemy znaleźć różnicę.

Non-generic stała pula:

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 // 

Ogólny stały basen:

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// 

Jak widać, w klasie Generic widzimy, istnieją dwa dodatkowe stałe, #9 i #10, w puli stałej, która mówi, że List ma ogólny typ String.

(i włączenie nowej wiedzy, że dowiedziałem się od Chris Jester-Young's answer)

Patrząc dalej w demontażu pliku klasy, nie ma odniesienia do stałej nr 10 tuż przed Code: block klasy Generic:

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

szesnastkowa 0A jest 10 w układzie dziesiętnym, które odnosi się do puli stałej #10:

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

Dlatego informacje z puli stałej są używane w celu wskazania, że ​​pole ma typ ogólny.