在軟件測試中淺談JAVA CLASS文件結構
從上圖中可以看到,一個 Java 類文件大致可以歸為 10 個項:
- Magic:該 項存放了一個 Java 類文件的魔數(magic number)和版本信息。一個 Java 類文件的前 4 個字節被稱為它的魔數。每個正確的 Java 類文件都是以 0xCAFEBABE 開頭的,這樣保證了 Java 虛擬機能很輕松的分辨出 Java 文件和非 Java 文件。
- Version:該項存放了 Java 類文件的版本信息,它對于一個 Java 文件具有重要的意義。因為 Java 技術一直在發展,所以類文件的格式也處在不斷變化之中。類文件的版本信息讓虛擬機知道如何去讀取并處理該類文件。
- Constant Pool:該 項存放了類中各種文字字符串、類名、方法名和接口名稱、final 變量以及對外部類的引用信息等常量。虛擬機必須為每一個被裝載的類維護一個常量池,常量池中存儲了相應類型所用到的所有類型、字段和方法的符號引用,因此 它在 Java 的動態鏈接中起到了核心的作用。常量池的大小——平均占到了整個類大小的 60% 左右。
- Access_flag:該項指明了該文件中定義的是類還是接口(一個 class 文件中只能有一個類或接口),同時還指名了類或接口的訪問標志,如 public,private, abstract 等信息。
- This Class:指向表示該類全限定名稱的字符串常量的指針。
- Super Class:指向表示父類全限定名稱的字符串常量的指針。
- Interfaces:一個指針數組,存放了該類或父類實現的所有接口名稱的字符串常量的指針。以上三項所指向的常量,特別是前兩項,在我們用 ASM 從已有類派生新類時一般需要修改:將類名稱改為子類名稱;將父類改為派生前的類名稱;如果有必要,增加新的實現接口。
- Fields:該項對類或接口中聲明的字段進行了細致的描述。需要注意的是,fields 列表中僅列出了本類或接口中的字段,并不包括從超類和父接口繼承而來的字段。
- Methods:該 項對類或接口中聲明的方法進行了細致的描述。例如方法的名稱、參數和返回值類型等。需要注意的是,methods 列表里僅存放了本類或本接口中的方法,并不包括從超類和父接口繼承而來的方法。使用 ASM 進行 AOP 編程,通常是通過調整 Method 中的指令來實現的。
- Class attributes:該項存放了在該文件中類或接口所定義的屬性的基本信息。
以下轉載自:http://edu.cryes.com/program/java/27962.html
Java文件結構用類似struct的描述如下:
ClassFile {
u4 magic; // 必須為: 0xCAFEBABE
u2 minor_version;
u2 major_version; //CLASS文件結構主次版本號 JAVA2支持45.0-46.0
u2 constant_pool_count; //記錄常量信息
cp_info constant_pool[constant_pool_count-1]; //計數從1開始
u2 access_flags; //class/interface訪問權限
u2 this_class; //指向constant_poll中的有效索引值
u2 super_class; //0或指向constant_poll中的有效索引值,對于interface必須為非0
u2 interfaces_count; //superinterfaces的個數
u2 interfaces[interfaces_count]; //計數[0,count-1) 對應constant_pool中的一個索引值
u2 fields_count;
field_info fields[fields_count]; //主要用于記錄class及實例中的變量
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
cp_info {
u1 tag;
u1 info[];
}
tag 意義如下:
CONSTANT_Class 7
CONSTANT_Fieldref 9
CONSTANT_Methodref 10
CONSTANT_InterfaceMethodref 11
CONSTANT_String 8
CONSTANT_Integer 3
CONSTANT_Float 4
CONSTANT_Long 5
CONSTANT_Double 6
CONSTANT_NameAndType 12
CONSTANT_Utf8 1
此時cp_info分別對應結構變化為
1. CONSTANT_Class
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
2. CONSTANT_Fieldref
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index; //constant_pool的索引,對應CONSTANT_Class_info
u2 name_and_type_index;//constant_pool的索引,對應CONSTANT_NameAndType_info
}
3. CONSTANT_Methodref
CONSTANT_Methodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
4. CONSTANT_InterfaceMethodref
CONSTANT_InterfaceMethodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
5. CONSTANT_String
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
6. CONSTANT_Integer
CONSTANT_Integer_info {
u1 tag;
u4 bytes;
}
7. CONSTANT_Float
CONSTANT_Float_info {
u1 tag;
u4 bytes;
}
8. CONSTANT_Long
CONSTANT_Long_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
9. CONSTANT_Double
CONSTANT_Double_info {
u1 tag;
u4 high_bytes;
u4 low_bytes
}
10.CONSTANT_NameAndType
CONSTANT_NameAndType_info {
u1 tag;
u2 name_index;
u2 descriptor_index;
}
11.CONSTANT_Utf8
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
access_flags意義如下:
ACC_PUBLIC 0x0001
ACC_FINAL 0x0010
ACC_SUPER 0x0020
ACC_INTERFACE 0x0200
ACC_ABSTRACT 0x0400
如果是interface那么必須置ACC_INTERFACE,如果沒有置ACC_INTERFACE則定義的是一個類而非接口。
如果設置了ACC_INTERFACE,那么ACC_ABSTRACT位也必須被設置,當然也可以設置ACC_PUBLIC。
ACC_SUPER用以表明invokespecial語義,Sun公司老的JAVA編譯器沒有設置ACC_SUPER,并且老的JVM
忽略ACC_SUPER位,但新的編譯器應該實現invokespecial語義。
其他未指明的位保留將來使用,并且編譯器應當將其置為0,同時Java虛擬機應當忽略他們。
this_class: constant_pool中的索引值,指向的元素的cp_info等價為CONSTANT_Class_info
CONSTANT_Class_info {
u1 tag; //必須為CONSTANT_Class (7)
u2 name_index; //為指向constant_pool中的一個索引值
}
name_index :指向的元素的cp_info等價為CONSTANT_Utf8_info
CONSTANT_Utf8_info {
u1 tag; //必須為CONSTANT_Utf8 (1)
u2 length;
u1 bytes[length]; //Utf8編碼的字符串
}
field_info {
u2 access_flags; //訪問控制權
u2 name_index; //constant_pool中的索引,對應于CONSTANT_Utf8_info描述。
u2 descriptor_index; //constant_pool中的索引,對應于CONSTANT_Utf8_info描述。
u2 attributes_count;
attribute_info attributes[attributes_count]; //attribute_info將在mothods后描述。
}
field_info中access_flages意義如下:
ACC_PUBLIC 0x0001
ACC_PRIVATE 0x0002
ACC_PROTECTED 0x0004
ACC_STATIC 0x0008
ACC_FINAL 0x0010
ACC_VOLATILE 0x0040
ACC_TRANSIENT 0x0080
其中很顯然不能同時為ACC_FINAL和ACC_VOLATILE ;且前三項是互斥的。
interface必須置ACC_PUBLIC, ACC_STATIC,ACC_FINAL位,且不能置其他位。
其他未指明的位保留將來使用,并且編譯器應當將其置為0,同時Java虛擬機應當忽略他們。
methods指明了類中的所有方法。
method_info {
u2 access_flags;
u2 name_index; //指向constant_pool的入口,對應為CONSTANT_Utf8_info
u2 descriptor_index; //指向constant_pool的入口,對應為CONSTANT_Utf8_info
u2 attributes_count;
attribute_info attributes[attributes_count];
//此處只能出現Code、Exceptions、Synthetic、Deprecated四種類型的屬性
}
access_flags訪問權描述如下:
ACC_PUBLIC 0x0001
ACC_PRIVATE 0x0002
ACC_PROTECTED 0x0004
ACC_STATIC 0x0008
ACC_FINAL 0x0010
ACC_SYNCHRONIZED 0x0020
ACC_NATIVE 0x0100
ACC_ABSTRACT 0x0400
ACC_STRICT 0x0800
attribute_info {
u2 attribute_name_index; //constant_pool中的索引,對應于CONSTANT_Utf8_info描述。
u4 attribute_length;
u1 info[attribute_length];
}
現在已經預定義的屬性有:
1. SourceFile : attribute_info被替代為:
SourceFile_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 sourcefile_index; //指向constant_pool中的一個CONSTANT_Utf8_info 結構。
}
2. ConstantValue : attribute_info被替代為:
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length; //必須為2
u2 constantvalue_index;
}
文章來源于領測軟件測試網 http://www.kjueaiud.com/