天天看點

Java位元組碼(.class檔案)格式詳解(一)

小介:去年在讀《深入解析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負責賦給他們,即它在任何靜态字段之前被指派。

對一個非靜态常量字段,該值會被虛拟機忽略,它的指派由生成的執行個體初始化函數(&lt;init&gt;)實作。如類:

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