2009-06-02 36 views

Trả lời

29

Chúng được lưu trữ trong các thuộc tính Signature; xem phần 4.8.8 của updated Java Virtual Machine Specification, cũng như phần 4.4.4 cho định dạng chữ ký loại trường.

Dưới đây là một ví dụ sử dụng javap -verbose java.util.Map:

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

Các Signature thuộc tính ở đây quy định cụ thể (nếu bạn đọc này như lớn về cuối nhỏ, giống như tất cả số lượng số nguyên trong các định dạng tập tin lớp JVM là) hồ bơi liên tục giá trị # 30 (30 = 0x1E).Vì vậy, chúng ta hãy có một cái nhìn ở đó:

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

Đọc điều này trong ngữ cảnh được quy định trong 4.4.4. Vì vậy, điều này sử dụng hai thông số loại, K extends java.lang.ObjectV extends java.lang.Object. Bản thân loại (Map) cũng mở rộng lớp java.lang.Object và không có giao diện.

14

Generics Java thực sự được thực hiện bởi type erasure, vì vậy không có thông tin loại nào trong bytecode.

Ví dụ, chúng ta hãy xem xét hai lớp đó khai báo một lĩnh vực List, một ở chung và người kia ở dạng phi-generic:

class NonGeneric { 
    List list; 
} 

Và,

class Generic { 
    List<String> list; 
} 

Trong cả hai trường hợp , bytecode kết quả như sau:

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 

Không có giới thiệu ce đến loại String được sử dụng trong ArrayList cũng không phải List. Vì vậy, chúng ta có thể thấy rằng generics thực sự được thực hiện bởi loại erasure.

Tuy nhiên, nếu chúng ta nhìn vào hồ bơi không đổi, chúng ta có thể tìm thấy sự khác biệt.

phi-generic hồ bơi liên tục:

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

Các generic hồ bơi liên tục:

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

Như có thể thấy, trong lớp Generic, chúng ta có thể thấy có hai hằng số phụ, #9#10, trong hồ bơi không đổi, đề cập đến rằng List có loại chung là String.

(Và kết hợp với kiến ​​thức mới mà tôi học được từ Chris Jester-Young's answer)

Nhìn xa hơn vào tháo dỡ của tập tin lớp học, có một tham chiếu đến hằng số # 10 ngay trước khi Code: block của lớp Generic:

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

giá trị thập lục phân 0A10 trong hệ thập phân, trong đó đề cập đến hồ bơi liên tục #10:

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

Do đó, thông tin từ nhóm không đổi được sử dụng để cho biết rằng một trường là một kiểu chung.

Các vấn đề liên quan