上善若水
          In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra
          posts - 146,comments - 147,trackbacks - 0

          小介:去年在讀《深入解析JVM》的時候寫的,記得當時還想著用自己的代碼解析字節碼的,最后只完成了一部分。現在都不知道還有沒有保留著,貌似Apache有現成的BCEL工程可以做這件事。當時也只是為了學習。這份資料主要參考《深入解析JVM》和《Java虛擬機規范》貌似是1.2版本的,整理出來的。里面包含了一些自己的理解和用實際代碼的測試。有興趣的童鞋可以研究研究。嘿嘿。要有錯誤也希望能為小弟指點出來,感激不盡。:)

          1.
          總體格式

          Class File format

          type

          descriptor

          remark

          u4

          magic

          0xCAFEBABE

          u2

          minor_version

           

          u2

          major_version

           

          u2

          constant_pool_count

           

          cp_info

          constant_pool[cosntant_pool_count – 1]

          index 0 is invalid

          u2

          access_flags

           

          u2

          this_class

           

          u2

          super_class

           

          u2

          interfaces_count

           

          u2

          interfaces[interfaces_count]

           

          u2

          fields_count

           

          field_info

          fields[fields_count]

           

          u2

          methods_count

           

          method_info

          methods[methods_count]

           

          u2

          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

          type

          descriptor

          remark

          u1

          tag

           

          u1

          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、bytechar、short類型都是用int類型存放,因而在常量池中沒有和它們對應的項。

          2.3.1    CONSTANT_Class_info

          用于記錄類或接口名(used to represent a class or an interface

          CONSTANT_Class_info format

          type

          descriptor

          remark

          u1

          tag

          CONSTANT_Class (7)

          u2

          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

          type

          descriptor

          remark

          u1

          tag

          CONSTANT_Integer (3)

          u4

          bytes

          整型常量值

           

          2.3.3    CONSTANT_Long_info

          用于記錄long類型的常量值(represent 8-byte numeric (long) constants:

          CONSTANT_Long_info

          type

          descriptor

          remark

          u1

          tag

          CONSTANT_Long (5)

          u4

          high_bytes

          長整型的高四位值

          u4

          low_bytes

          長整型的低四位值

           

          2.3.4    CONSTANT_Float_info

          用于記錄float類型的常量值(represent 4-byte numeric (float) constants:

          CONSTANT_Float_info

          type

          descriptor

          remark

          u1

          tag

          CONSTANT_Float(4)

          u4

          bytes

          單精度浮點型常量值

          幾個特殊值:0x7f800000 => Float.POSITIVE_INFINITY、0xff800000 => Float.NEGATIVE_INFINITY、

                          0x7f800001 to 0x7fffffff => Float.NaN0xff800001 to 0xffffffff => Float.NaN

           

          2.3.5    CONSTANT_Double_info

          用于記錄double類型的常量值(represent 8-byte numeric (double) constants:

          CONSTANT_Double_info

          type

          descriptor

          remark

          u1

          tag

          CONSTANT_Double(6)

          u4

          high_bytes

          雙精度浮點的高四位值

          u4

          low_bytes

          雙精度浮點的低四位值

          幾個特殊值: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

          type

          descriptor

          remark

          u1

          tag

          CONSTANT_String(8)

          u2

          string_index

          constant_pool中的索引,CONSTANT_Utf8_info類型。表示String類型值。

           

          2.3.7    CONSTANT_Fieldref_info

          用于記錄字段信息(包括類或接口中定義的字段以及代碼中使用到的字段)。

          CONSTANT_Fieldref_info

          type

          descriptor

          remark

          u1

          tag

          CONSTANT_Fieldref(9)

          u2

          class_index

          constant_pool中的索引,CONSTANT_Class_info類型。記錄定義該字段的類或接口。

          u2

          name_and_type_index

          constant_pool中的索引,CONSTANT_NameAndType_info類型。指定類或接口中的字段名(name)和字段描述符(descriptor)。

           

          2.3.8    CONSTANT_Methodref_info

          用于記錄方法信息(包括類中定義的方法以及代碼中使用到的方法)。

          CONSTANT_Methodref_info

          type

          descriptor

          remark

          u1

          tag

          CONSTANT_Methodref(10)

          u2

          class_index

          constant_pool中的索引,CONSTANT_Class_info類型。記錄定義該方法的類。

          u2

          name_and_type_index

          constant_pool中的索引,CONSTANT_NameAndType_info類型。指定類中扽方法名(name)和方法描述符(descriptor)。

           

          2.3.9    CONSTANT_InterfaceMethodref_info

          用于記錄接口中的方法信息(包括接口中定義的方法以及代碼中使用到的方法)。

          CONSTANT_InterfaceMethodref_info

          type

          descriptor

          remark

          u1

          tag

          CONSTANT_InterfaceMethodref(11)

          u2

          class_index

          constant_pool中的索引,CONSTANT_Class_info類型。記錄定義該方法的接口。

          u2

          name_and_type_index

          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

          type

          descriptor

          remark

          u1

          tag

          CONSTANT_NameAndType (12)

          u2

          name_index

          constant_pool中的索引,CONSTANT_Utf8_info類型。指定字段或方法的名稱。

          u2

          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 :

          http://download.ora

          cle.com/javase/1.4.2/docs/api/java/io/DataInputStream.html

          CONSTANT_Utf8_info

          type

          descriptor

          remark

          u1

          tag

          CONSTANT_Utf8 (1)

          u2

          length

          bytes所代表

          的字符串的長度

          u1

          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_FINALACC_SUPER、ACC_ENUM

          ACC_ABSTRACT

          0x0400

          抽象類,無法實例化。不可和ACC_FINAL同時設置。

          ACC_SYNTHETIC

          0x1000

          synthetic,由編譯器產生,不存在于源代碼中。

          ACC_ANNOTATION

          0x2000

          注解類型(annotation),需同時設置:ACC_INTERFACEACC_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等。

          field_info

          type

          descriptor

          remark

          u2

          access_flags

          記錄字段的訪問權限。見2.8.1

          u2

          name_index

          constant_pool中的索引,CONSTANT_Utf8_info類型。指定字段的名稱。

          u2

          descriptor_index

          constant_pool中的索引,CONSTANT_Utf8_info類型,指定字段的描述符(見附錄C)。

          u2

          attributes_count

          attributes包含的項目數。

          attribute_info

          attributes[attributes_count]

          字段中包含的Attribute集合。見2.8.2-2.8.7

          注:fields中的項目和CONSTANT_Fieldref_info中的項目部分信息是相同的,他們主要的區別是CONSTANT_Fieldref_info中的項目不僅包含了類或接口中定義的字段,還包括在字節碼中使用到的字段信息。不過這里很奇怪,為什么field_info結構中不把name_indexdescriptor_index合并成fieldref_index,這樣的class文件不是更加緊湊嗎??不知道這是sun因為某些原因故意這樣設計還是這是他們的失誤??

           

          2.8.1    字段訪問權限

          字段的訪問權限

          Flag Name

          Value

          Remarks

          ACC_PUBLIC

          0x0001

          pubilc,包外可訪問。

          ACC_PRIVATE

          0x0002

          private,只可在類內訪問。

          ACC_PROTECTED

          0x0004

          protected,類內和子類中可訪問。

          ACC_STATIC

          0x0008

          static,靜態。

          ACC_FINAL

          0x0010

          final,常量。

          ACC_VOILATIE

          0x0040

          volatile,直接讀寫內存,不可被緩存。不可和ACC_FINAL一起使用。

          ACC_TRANSIENT

          0x0080

          transient,在序列化中被忽略的字段。

          ACC_SYNTHETIC

          0x1000

          synthetic,由編譯器產生,不存在于源代碼中。

          ACC_ENUM

          0x4000

          enum,枚舉類型字段

          注:接口中的字段必須同時設置:ACC_PUBLICACC_STATICACC_FINAL

           

          2.8.2    ConstantValue Attribute JVM識別)

          ConstantValue Attribute

          type

          descriptor

          remark

          u2

          attribute_name_index

          constant_pool中的索引,CONSTANT_Utf8_info類型。指定Attribute的名稱(“ConstantValue”)。

          u4

          attribute_length

          Attribute內容的字節長度(固定值:2

          u2

          constant_value_index

          constant_pool中的索引,

          CONSTANT_Integer_infointbooleanchar、shortbyte)、

          CONSTANT_Float_infofloat)、

          Constant_Double_infodouble)、

          CONSTANT_Long_infolong

          CONSTANT_String_infoString)類型

          每個常量字段(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]

               5 bipush 30

               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

                                                                                                                                  于2010-12-19

          posted on 2011-09-05 23:24 DLevin 閱讀(20019) 評論(3)  編輯  收藏 所屬分類: 深入JVM

          FeedBack:
          # re: Java字節碼(.class文件)格式詳解(一)
          2011-09-05 23:51 | 步步為營
          很細,很深入  回復  更多評論
            
          # re: Java字節碼(.class文件)格式詳解(一)[未登錄]
          2011-09-06 07:15 | feenn
          不錯,接著跟蹤  回復  更多評論
            
          # re: Java字節碼(.class文件)格式詳解(一)
          2011-09-06 09:55 | Red Wolf
          不錯,也研究過段時間  回復  更多評論
            
          主站蜘蛛池模板: 增城市| 铜川市| 宜城市| 三台县| 黔西| 岑溪市| 城市| 象山县| 临洮县| 新河县| 本溪| 中西区| 宁明县| 新余市| 阿城市| 东乌| 喀喇| 沐川县| 克山县| 阿瓦提县| 巧家县| 大余县| 哈巴河县| 通山县| 方正县| 昂仁县| 扎兰屯市| 普兰县| 桐城市| 长沙县| 璧山县| 金平| 嵊州市| 龙口市| 平乐县| 司法| 元氏县| 壶关县| 营口市| 永和县| 兴和县|