小介:去年在讀《深入解析jvm》的時候寫的,記得當時還想着用自己的代碼解析位元組碼的,最後隻完成了一部分。現在都不知道還有沒有保留着,貌似apache有現成的bcel工程可以做這件事。當時也隻是為了學習。這份資料主要參考《深入解析jvm》和《java虛拟機規範》貌似是1.2版本的,整理出來的。裡面包含了一些自己的了解和用實際代碼的測試。有興趣的童鞋可以研究研究。嘿嘿。要有錯誤也希望能為小弟指點出來,感激不盡。:)
1.總體格式
class file format
type
descriptor
remark
u4
magic
0xcafebabe
u2
minor_version
major_version
constant_pool_count
cp_info
constant_pool[cosntant_pool_count – 1]
index 0 is invalid
access_flags
this_class
super_class
interfaces_count
interfaces[interfaces_count]
fields_count
field_info
fields[fields_count]
methods_count
method_info
methods[methods_count]
attributes_count
attribute_info
attributes[attributes_count]
2. 格式詳解
2.1 magic
magic被稱為“魔數”,用來辨別.class檔案的開頭。所有合法的.class位元組碼都應該是該數開頭,占4個位元組。
2.2 major_version.minor_version
major_version.minor_version合在一起形成目前.class檔案的版本号,該版本号一般由編譯器産生,并且由sun定義。如59.0。它們一起占4個位元組。
2.3 constant_pool
在java位元組碼中,有一個常量池,用來存放不同類型的常量。由于java設計的目的之一就是位元組碼需要經網絡傳輸的,因而位元組碼需要比較緊湊,以減少網絡傳輸的流量和時間。常量池的存在則可以讓一些相同類型的值通過索引的方式從常量池中找到,而不是在不同地方有不同拷貝,縮減了位元組碼的大小。
每個常量池中的項是通過cp_info的類型來表示的,它的格式如下:
cp_info format
u1
tag
info[]
這裡tag用來表示目前常量池不同類型的項。info中存放常量池項中存放的資料。
tag中表示的資料類型:
constant_class_info (7)、
constant_integer_info (3)、
constant_long_info (5)、
constant_float_info (4)、
constant_double_info (6)、
constant_string_info (8)、
constant_fieldref_info (9)、
constant_methodref_info (10)、
constant_interfacemethodref_info (11)、
constant_nameandtype_info (12)、
constant_utf8_info (1)、
注:在java位元組碼中,所有boolean、byte、char、short類型都是用int類型存放,因而在常量池中沒有和它們對應的項。
2.3.1 constant_class_info
用于記錄類或接口名(used to represent a class or an interface)
constant_class_info format
constant_class (7)
name_index
constant_pool中的索引,constant_utf8_info類型。表示類或接口名。
注:在java位元組碼中,類和接口名不同于源碼中的名字,詳見附件a.
2.3.2 constant_integer_info
用于記錄int類型的常量值(represent 4-byte numeric (int) constants:)
constant_integer_info
constant_integer (3)
bytes
整型常量值
2.3.3 constant_long_info
用于記錄long類型的常量值(represent 8-byte numeric (long) constants:)
constant_long_info
constant_long (5)
high_bytes
長整型的高四位值
low_bytes
長整型的低四位值
2.3.4 constant_float_info
用于記錄float類型的常量值(represent 4-byte numeric (float) constants:)
constant_float_info
constant_float(4)
單精度浮點型常量值
幾個特殊值:0x7f800000 => float.positive_infinity、0xff800000 => float.negative_infinity、
0x7f800001 to 0x7fffffff => float.nan、0xff800001 to 0xffffffff => float.nan
2.3.5 constant_double_info
用于記錄double類型的常量值(represent 8-byte numeric (double) constants:)
constant_double_info
constant_double(6)
雙精度浮點的高四位值
雙精度浮點的低四位值
幾個特殊值:0x7ff0000000000000l => double.positive_infinity、
0xfff0000000000000l => double.negative_infinity
0x7ff0000000000001l to 0x7fffffffffffffffl => double.nan 、
0xfff0000000000001l to 0xffffffffffffffffl => double.nan
2.3.6 constant_string_info
用于記錄常量字元串的值(represent constant objects of the type string:)
constant_string_info
constant_string(8)
string_index
constant_pool中的索引,constant_utf8_info類型。表示string類型值。
2.3.7 constant_fieldref_info
用于記錄字段資訊(包括類或接口中定義的字段以及代碼中使用到的字段)。
constant_fieldref_info
constant_fieldref(9)
class_index
constant_pool中的索引,constant_class_info類型。記錄定義該字段的類或接口。
name_and_type_index
constant_pool中的索引,constant_nameandtype_info類型。指定類或接口中的字段名(name)和字段描述符(descriptor)。
2.3.8 constant_methodref_info
用于記錄方法資訊(包括類中定義的方法以及代碼中使用到的方法)。
constant_methodref_info
constant_methodref(10)
constant_pool中的索引,constant_class_info類型。記錄定義該方法的類。
constant_pool中的索引,constant_nameandtype_info類型。指定類中扽方法名(name)和方法描述符(descriptor)。
2.3.9 constant_interfacemethodref_info
用于記錄接口中的方法資訊(包括接口中定義的方法以及代碼中使用到的方法)。
constant_interfacemethodref_info
constant_interfacemethodref(11)
constant_pool中的索引,constant_class_info類型。記錄定義該方法的接口。
constant_pool中的索引,constant_nameandtype_info類型。指定接口中的方法名(name)和方法描述符(descriptor)。
2.3.10 constant_nameandtype_info
記錄方法或字段的名稱(name)和描述符(descriptor)(represent a field or method, without indicating which class or interface type it belongs to:)。
constant_nameandtype_info
constant_nameandtype (12)
constant_pool中的索引,constant_utf8_info類型。指定字段或方法的名稱。
descriptor_index
constant_pool中的索引,constant_utf8_info類型。指定字段或方法的描述符(見附錄c)
2.3.11 constant_utf8_info
記錄字元串的值(represent constant string values. string content is encoded in modified utf-8.)
modifie
d utf-8 refer to :
<a href="http://download.oracle.com/javase/1.4.2/docs/api/java/io/datainputstream.html">http://download.ora</a>
<a href="http://download.oracle.com/javase/1.4.2/docs/api/java/io/datainputstream.html">cle.com/javase/1.4.2/docs/api/java/io/datainputstream.html</a>
constant_utf8_info
constant_utf8 (1)
length
bytes所代表
的字元串的長度
bytes[length]
字元串的byte資料,可以通過datainputstream中的readutf()方法(執行個體方法或靜态方法讀取該二進制的字元串的值。)
2.4 access_flags
指定類或接口的通路權限。
類或接口的通路權限
flag name
value
remarks
acc_public
0x0001
pubilc,包外可通路。
acc_final
0x0010
final,不能有子類。
acc_super
0x0020
用于相容早期編譯器,新編譯器都設定該标記,以在使用 invokespecial指令時對子類方法做特定處理。
acc_interface
0x0200
接口,同時需要設定:acc_abstract。不可同時設定:acc_final、acc_super、acc_enum
acc_abstract
0x0400
抽象類,無法執行個體化。不可和acc_final同時設定。
acc_synthetic
0x1000
synthetic,由編譯器産生,不存在于源代碼中。
acc_annotation
0x2000
注解類型(annotation),需同時設定:acc_interface、acc_abstract
acc_enum
0x4000
枚舉類型
2.5 this_class
this_class是指向constant pool的索引值,該值必須是constant_class_info類型,指定目前位元組碼定義的類或接口。
2.6 super_class
super_class是指向constant pool的索引值,該值必須是constant_class_info類型,指定目前位元組碼定義的類或接口的直接父類。隻有object類才沒有直接父類,此時該索引值為0。并且父類不能是final類型。接口的父類都是object類。
2.7 interfaces
interfaces數組記錄所有目前類或接口直接實作的接口。interfaces數組中的每項值都是一個指向constant pool的索引值,這些值必須是constant_class_info類型。數組中接口的順序和源代碼中接口定義的順序相同。
2.8 fields
fields數組記錄了類或接口中的所有字段,包括執行個體字段和靜态字段,但不包含父類或父接口中定義的字段。fields數組中每項都是field_info類型值,它描述了字段的詳細資訊,如名稱、描述符、字段中的attribute等。
記錄字段的通路權限。見2.8.1
constant_pool中的索引,constant_utf8_info類型。指定字段的名稱。
constant_pool中的索引,constant_utf8_info類型,指定字段的描述符(見附錄c)。
attributes包含的項目數。
字段中包含的attribute集合。見2.8.2-2.8.7
注:fields中的項目和constant_fieldref_info中的項目部分資訊是相同的,他們主要的差別是constant_fieldref_info中的項目不僅包含了類或接口中定義的字段,還包括在位元組碼中使用到的字段資訊。不過這裡很奇怪,為什麼field_info結構中不把name_index和descriptor_index合并成fieldref_index,這樣的class檔案不是更加緊湊嗎??不知道這是sun因為某些原因故意這樣設計還是這是他們的失誤??
2.8.1 字段通路權限
字段的通路權限
acc_private
0x0002
private,隻可在類内通路。
acc_protected
0x0004
protected,類内和子類中可通路。
acc_static
0x0008
static,靜态。
final,常量。
acc_voilatie
0x0040
volatile,直接讀寫記憶體,不可被緩存。不可和acc_final一起使用。
acc_transient
0x0080
transient,在序列化中被忽略的字段。
enum,枚舉類型字段
注:接口中的字段必須同時設定:acc_public、acc_static、acc_final
2.8.2 constantvalue attribute (jvm識别)
constantvalue attribute
attribute_name_index
constant_pool中的索引,constant_utf8_info類型。指定attribute的名稱(“constantvalue”)。
attribute_length
該attribute内容的位元組長度(固定值:2)
constant_value_index
constant_pool中的索引,
constant_integer_info(int,boolean,char、short、byte)、
constant_float_info(float)、
constant_double_info(double)、
constant_long_info(long)
constant_string_info(string)類型
每個常量字段(final,靜态常量或執行個體常量)都包含有且僅有一個constantvalue attribute。constantvalue attribute結構用于存儲一個字段的常量值。
對一個靜态常量字段,該常量值會在類或接口被初始化之前,由jvm負責賦給他們,即它在任何靜态字段之前被指派。
對一個非靜态常量字段,該值會被虛拟機忽略,它的指派由生成的執行個體初始化函數(<init>)實作。如類:
class a {
public static final int fa = 10;
public final int fa2 = 30;
private static int sa = 20;
static {
sa = 30;
}
}
生成的位元組碼如下:
// compiled from test.java (version 1.6 : 50.0, super bit)
class org.levin.insidejvm.miscs.staticinit.a {
public static final int fa = 10;
public final int fa2 = 30;
private static int sa;
static {};
0 bipush 20
2 putstatic org.levin.insidejvm.miscs.staticinit.a.sa : int [16]
5 bipush 30
7 putstatic org.levin.insidejvm.miscs.staticinit.a.sa : int [16]
10 return
public a();
0 aload_0 [this]
1 invokespecial java.lang.object() [21]
4 aload_0 [this]
7 putfield org.levin.insidejvm.miscs.staticinit.a.fa2 : int [23]
10 return
2.8.3 synthetic attribute
參考2.11.1
2.8.4 signature attribute
參考2.11.2
2.8.5 deprecated attribute
參考2.11.3
2.8.6 runtimevisibleannotations attribute
參考2.11.4
2.8.7 runtimeinvisibleannotations attribute
參考2.11.5