2009-06-02 14 views

Respuesta

29

Se almacenan en los atributos Signature; ver la sección 4.8.8 del updated Java Virtual Machine Specification, así como la sección 4.4.4 para el formato de la firma del tipo de campo.

Aquí hay un ejemplo usando javap -verbose java.util.Map:

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

El atributo Signature aquí especifica (si lee esto como big-endian, como todas las cantidades de números enteros en el formato de archivo de clase JVM son) el valor de la piscina constante # 30 (30 = 0x1E).Así que echemos un vistazo allí:

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

Lea esto en el contexto de la gramática especificada en 4.4.4. Por lo tanto, esto utiliza dos parámetros de tipo, K extends java.lang.Object y V extends java.lang.Object. El tipo en sí (Map) también extiende la clase java.lang.Object, y no tiene interfaces.

14

Los genéricos de Java están efectivamente implementados por type erasure, por lo que no hay información de tipo en el bytecode.

Por ejemplo, vamos a echar un vistazo dos clases que declaran un campo List, una en genérico y la otra en forma no genérico:

class NonGeneric { 
    List list; 
} 

Y,

class Generic { 
    List<String> list; 
} 

En ambos casos , el bytecode resultante es el siguiente:

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 

No hay referencias ce al tipo String utilizado en el ArrayList o List. Entonces, podemos ver que los genéricos se implementan por borrado de tipos.

Sin embargo, si miramos el conjunto constante, podemos encontrar una diferencia.

El no genérico del grupo de constantes:

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

El genérico de memoria constante:

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

Como puede verse, en la clase Generic, podemos ver que hay dos constantes adicionales, #9 y #10, en el grupo constante, que menciona que el List tiene el tipo genérico String.

(y la incorporación de nuevos conocimientos que he aprendido de Chris Jester-Young's answer)

Mirando más en el desmontaje del archivo de clase, hay una referencia a la constante # 10 justo antes de la Code: block de la clase Generic:

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

el valor hexadecimal 0A es 10 en decimal, que se refiere a la piscina constante #10:

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

Por lo tanto, la información del conjunto constante se utiliza para indicar que un campo es de tipo genérico.

Cuestiones relacionadas