2009-06-02 18 views

risposta

29

Sono memorizzati negli attributi Signature; vedere la sezione 4.8.8 di updated Java Virtual Machine Specification, nonché la sezione 4.4.4 per il formato della firma del tipo di campo.

Ecco un esempio utilizzando javap -verbose java.util.Map:

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

L'attributo Signature qui specifica (se leggi questo come big-endian, come tutte le quantità interi nel formato di file di classe JVM sono) piscina costante valore # 30 (30 = 0x1E).Diamo un'occhiata:

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

Leggere nel contesto della grammatica specificata in 4.4.4. Quindi, utilizza due parametri di tipo, K extends java.lang.Object e V extends java.lang.Object. Il tipo stesso (Map) estende anche la classe java.lang.Object e nessuna interfaccia.

14

I generici Java sono effettivamente implementati da type erasure, quindi non ci sono informazioni sul tipo nel bytecode.

Per esempio, diamo uno sguardo due classi che dichiarano un campo List, uno nel generico e l'altro in forma non generica:

class NonGeneric { 
    List list; 
} 

E,

class Generic { 
    List<String> list; 
} 

In entrambi i casi , il bytecode risultante è il seguente:

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 

Non vi è alcun riferimento ce al tipo String utilizzato nel ArrayListList. Quindi, possiamo vedere che i farmaci generici sono effettivamente implementati dalla cancellazione dei tipi.

Tuttavia, se guardiamo al pool costante, possiamo trovare una differenza.

Il non generico piscina costante:

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

La generica piscina costante:

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

Come si può vedere, nella classe Generic, possiamo vedere ci sono due costanti in più, #9 e #10, nel pool costante, che indica che il List ha il tipo generico di String.

(e incorporando nuove conoscenze che ho imparato da Chris Jester-Young's answer)

Guardando più al smontaggio del file di classe, c'è un riferimento alla costante # 10 a destra prima del Code: block della classe Generic:

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

il valore esadecimale 0A è 10 in decimale, che si riferisce alla piscina costante #10:

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

Pertanto, le informazioni del pool costante vengono utilizzate per indicare che un campo è di tipo generico.

Problemi correlati