解析一个Java字节码文件


1.ClassFile结构(Java虚拟机规范 4.1 )

ClassFile {
  u4 magic;
  u2 minor_version;
  u2 major_version;
  u2 constant_pool_count;
  cp_info constant_pool[constant_pool_count-1];
  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. 一个示例程序的源代码

 1 import java.util.logging.Logger;
 2 
 3 import sun.misc.BASE64Encoder;
 4 
 5 public class BASE64Util {
 6 
 7         private static Logger log = Logger.getLogger(BASE64Util.class.getName());
 8 
 9         public String encodeBase64(String message) {
10                 BASE64Encoder encoder = new BASE64Encoder();
11                 String result = encoder.encodeBuffer(message.getBytes());
12                 log.info(message);
13                 log.info(result);
14                 return result;
15         }
16         public static void main(String[] args) {
17                 BASE64Util base64Util = new BASE64Util();
18                 String message = "hello world";
19                 base64Util.encodeBase64(message);
20         }
21 }

 

3.编译后的字节码

 1 0000000: cafe babe 0000 0033 0038 0a00 0e00 1c07  .......3.8......
 2 0000010: 001d 0a00 0200 1c0a 001e 001f 0a00 0200  ................
 3 0000020: 2009 0008 0021 0a00 2200 2307 0024 0a00   ....!..".#..$..
 4 0000030: 0800 1c08 0025 0a00 0800 260a 0027 0028  .....%....&..'.(
 5 0000040: 0a00 2200 2907 002a 0100 036c 6f67 0100  ..".)..*...log..
 6 0000050: 1a4c 6a61 7661 2f75 7469 6c2f 6c6f 6767  .Ljava/util/logg
 7 0000060: 696e 672f 4c6f 6767 6572 3b01 0006 3c69  ing/Logger;...<i
 8 0000070: 6e69 743e 0100 0328 2956 0100 0443 6f64  nit>...()V...Cod
 9 0000080: 6501 000f 4c69 6e65 4e75 6d62 6572 5461  e...LineNumberTa
10 0000090: 626c 6501 000c 656e 636f 6465 4261 7365  ble...encodeBase
11 00000a0: 3634 0100 2628 4c6a 6176 612f 6c61 6e67  64..&(Ljava/lang
12 00000b0: 2f53 7472 696e 673b 294c 6a61 7661 2f6c  /String;)Ljava/l
13 00000c0: 616e 672f 5374 7269 6e67 3b01 0004 6d61  ang/String;...ma
14 00000d0: 696e 0100 1628 5b4c 6a61 7661 2f6c 616e  in...([Ljava/lan
15 00000e0: 672f 5374 7269 6e67 3b29 5601 0008 3c63  g/String;)V...<c
16 00000f0: 6c69 6e69 743e 0100 0a53 6f75 7263 6546  linit>...SourceF
17 0000100: 696c 6501 000f 4241 5345 3634 5574 696c  ile...BASE64Util
18 0000110: 2e6a 6176 610c 0011 0012 0100 1673 756e  .java........sun
19 0000120: 2f6d 6973 632f 4241 5345 3634 456e 636f  /misc/BASE64Enco
20 0000130: 6465 7207 002b 0c00 2c00 2d0c 002e 002f  der..+..,.-..../
21 0000140: 0c00 0f00 1007 0030 0c00 3100 3201 000a  .......0..1.2...
22 0000150: 4241 5345 3634 5574 696c 0100 0b68 656c  BASE64Util...hel
23 0000160: 6c6f 2077 6f72 6c64 0c00 1500 1607 0033  lo world.......3
24 0000170: 0c00 3400 350c 0036 0037 0100 106a 6176  ..4.5..6.7...jav
25 0000180: 612f 6c61 6e67 2f4f 626a 6563 7401 0010  a/lang/Object...
26 0000190: 6a61 7661 2f6c 616e 672f 5374 7269 6e67  java/lang/String
27 00001a0: 0100 0867 6574 4279 7465 7301 0004 2829  ...getBytes...()
28 00001b0: 5b42 0100 0c65 6e63 6f64 6542 7566 6665  [B...encodeBuffe
29 00001c0: 7201 0016 285b 4229 4c6a 6176 612f 6c61  r...([B)Ljava/la
30 00001d0: 6e67 2f53 7472 696e 673b 0100 186a 6176  ng/String;...jav
31 00001e0: 612f 7574 696c 2f6c 6f67 6769 6e67 2f4c  a/util/logging/L
32 00001f0: 6f67 6765 7201 0004 696e 666f 0100 1528  ogger...info...(
33 0000200: 4c6a 6176 612f 6c61 6e67 2f53 7472 696e  Ljava/lang/Strin
34 0000210: 673b 2956 0100 0f6a 6176 612f 6c61 6e67  g;)V...java/lang
35 0000220: 2f43 6c61 7373 0100 0767 6574 4e61 6d65  /Class...getName
36 0000230: 0100 1428 294c 6a61 7661 2f6c 616e 672f  ...()Ljava/lang/
37 0000240: 5374 7269 6e67 3b01 0009 6765 744c 6f67  String;...getLog
38 0000250: 6765 7201 002e 284c 6a61 7661 2f6c 616e  ger...(Ljava/lan
39 0000260: 672f 5374 7269 6e67 3b29 4c6a 6176 612f  g/String;)Ljava/
40 0000270: 7574 696c 2f6c 6f67 6769 6e67 2f4c 6f67  util/logging/Log
41 0000280: 6765 723b 0021 0008 000e 0000 0001 000a  ger;.!..........
42 0000290: 000f 0010 0000 0004 0001 0011 0012 0001  ................
43 00002a0: 0013 0000 001d 0001 0001 0000 0005 2ab7  ..............*.
44 00002b0: 0001 b100 0000 0100 1400 0000 0600 0100  ................
45 00002c0: 0000 0500 0100 1500 1600 0100 1300 0000  ................
46 00002d0: 4900 0200 0400 0000 21bb 0002 59b7 0003  I.......!...Y...
47 00002e0: 4d2c 2bb6 0004 b600 054e b200 062b b600  M,+......N...+..
48 00002f0: 07b2 0006 2db6 0007 2db0 0000 0001 0014  ....-...-.......
49 0000300: 0000 0016 0005 0000 000a 0008 000b 0011  ................
50 0000310: 000c 0018 000d 001f 000e 0009 0017 0018  ................
51 0000320: 0001 0013 0000 0036 0002 0003 0000 0012  .......6........
52 0000330: bb00 0859 b700 094c 120a 4d2b 2cb6 000b  ...Y...L..M+,...
53 0000340: 57b1 0000 0001 0014 0000 0012 0004 0000  W...............
54 0000350: 0011 0008 0012 000b 0013 0011 0014 0008  ................
55 0000360: 0019 0012 0001 0013 0000 0025 0001 0000  ...........%....
56 0000370: 0000 000d 1300 08b6 000c b800 0db3 0006  ................
57 0000380: b100 0000 0100 1400 0000 0600 0100 0000  ................
58 0000390: 0700 0100 1a00 0000 0200 1b              ...........

4. 字节码说明

1)    

u4 magic 魔数 CAFEBABE

2) 

(u2,u2) (minor_version,major_version) jdk 1.7 

3) 

u2 constant_pool_count,0038 转换成10进制为56,意味着常量池索引为1~55

4) 常量池解析

  4.1) 常量池数据结构

1 cp_info {
2     u1 tag;
3     u1 info[];
4 }

  4.2) 常量池的 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
CONSTANT_MethodHandle 15
CONSTANT_MethodType 16
CONSTANT_InvokeDynamic 18
   

    常量池内容:

    

  1 [tom@localhost ch04]$ javap -verbose -c BASE64Util.class 
  2 Classfile /home/tom/mywork/hotspotws/ch04/BASE64Util.class
  3   Last modified Jun 12, 2016; size 923 bytes
  4   MD5 checksum 68b6eaa90d79a8133289624952dc4e3d
  5   Compiled from "BASE64Util.java"
  6 public class BASE64Util
  7   SourceFile: "BASE64Util.java"
  8   minor version: 0
  9   major version: 51
 10   flags: ACC_PUBLIC, ACC_SUPER
 11 Constant pool:
 12    #1 = Methodref          #14.#28        //  java/lang/Object."<init>":()V
 13    #2 = Class              #29            //  sun/misc/BASE64Encoder
 14    #3 = Methodref          #2.#28         //  sun/misc/BASE64Encoder."<init>":()V
 15    #4 = Methodref          #30.#31        //  java/lang/String.getBytes:()[B
 16    #5 = Methodref          #2.#32         //  sun/misc/BASE64Encoder.encodeBuffer:([B)Ljava/lang/String;
 17    #6 = Fieldref           #8.#33         //  BASE64Util.log:Ljava/util/logging/Logger;
 18    #7 = Methodref          #34.#35        //  java/util/logging/Logger.info:(Ljava/lang/String;)V
 19    #8 = Class              #36            //  BASE64Util
 20    #9 = Methodref          #8.#28         //  BASE64Util."<init>":()V
 21   #10 = String             #37            //  hello world
 22   #11 = Methodref          #8.#38         //  BASE64Util.encodeBase64:(Ljava/lang/String;)Ljava/lang/String;
 23   #12 = Methodref          #39.#40        //  java/lang/Class.getName:()Ljava/lang/String;
 24   #13 = Methodref          #34.#41        //  java/util/logging/Logger.getLogger:(Ljava/lang/String;)Ljava/util/logging/Logger;
 25   #14 = Class              #42            //  java/lang/Object
 26   #15 = Utf8               log
 27   #16 = Utf8               Ljava/util/logging/Logger;
 28   #17 = Utf8               <init>
 29   #18 = Utf8               ()V
 30   #19 = Utf8               Code
 31   #20 = Utf8               LineNumberTable
 32   #21 = Utf8               encodeBase64
 33   #22 = Utf8               (Ljava/lang/String;)Ljava/lang/String;
 34   #23 = Utf8               main
 35   #24 = Utf8               ([Ljava/lang/String;)V
 36   #25 = Utf8               <clinit>
 37   #26 = Utf8               SourceFile
 38   #27 = Utf8               BASE64Util.java
 39   #28 = NameAndType        #17:#18        //  "<init>":()V
 40   #29 = Utf8               sun/misc/BASE64Encoder
 41   #30 = Class              #43            //  java/lang/String
 42   #31 = NameAndType        #44:#45        //  getBytes:()[B
 43   #32 = NameAndType        #46:#47        //  encodeBuffer:([B)Ljava/lang/String;
 44   #33 = NameAndType        #15:#16        //  log:Ljava/util/logging/Logger;
 45   #34 = Class              #48            //  java/util/logging/Logger
 46   #35 = NameAndType        #49:#50        //  info:(Ljava/lang/String;)V
 47   #36 = Utf8               BASE64Util
 48   #37 = Utf8               hello world
 49   #38 = NameAndType        #21:#22        //  encodeBase64:(Ljava/lang/String;)Ljava/lang/String;
 50   #39 = Class              #51            //  java/lang/Class
 51   #40 = NameAndType        #52:#53        //  getName:()Ljava/lang/String;
 52   #41 = NameAndType        #54:#55        //  getLogger:(Ljava/lang/String;)Ljava/util/logging/Logger;
 53   #42 = Utf8               java/lang/Object
 54   #43 = Utf8               java/lang/String
 55   #44 = Utf8               getBytes
 56   #45 = Utf8               ()[B
 57   #46 = Utf8               encodeBuffer
 58   #47 = Utf8               ([B)Ljava/lang/String;
 59   #48 = Utf8               java/util/logging/Logger
 60   #49 = Utf8               info
 61   #50 = Utf8               (Ljava/lang/String;)V
 62   #51 = Utf8               java/lang/Class
 63   #52 = Utf8               getName
 64   #53 = Utf8               ()Ljava/lang/String;
 65   #54 = Utf8               getLogger
 66   #55 = Utf8               (Ljava/lang/String;)Ljava/util/logging/Logger;
 67 {
 68   public BASE64Util();
 69     flags: ACC_PUBLIC
 70     Code:
 71       stack=1, locals=1, args_size=1
 72          0: aload_0       
 73          1: invokespecial #1                  // Method java/lang/Object."<init>":()V
 74          4: return        
 75       LineNumberTable:
 76         line 5: 0
 77 
 78   public java.lang.String encodeBase64(java.lang.String);
 79     flags: ACC_PUBLIC
 80     Code:
 81       stack=2, locals=4, args_size=2
 82          0: new           #2                  // class sun/misc/BASE64Encoder
 83          3: dup           
 84          4: invokespecial #3                  // Method sun/misc/BASE64Encoder."<init>":()V
 85          7: astore_2      
 86          8: aload_2       
 87          9: aload_1       
 88         10: invokevirtual #4                  // Method java/lang/String.getBytes:()[B
 89         13: invokevirtual #5                  // Method sun/misc/BASE64Encoder.encodeBuffer:([B)Ljava/lang/String;
 90         16: astore_3      
 91         17: getstatic     #6                  // Field log:Ljava/util/logging/Logger;
 92         20: aload_1       
 93         21: invokevirtual #7                  // Method java/util/logging/Logger.info:(Ljava/lang/String;)V
 94         24: getstatic     #6                  // Field log:Ljava/util/logging/Logger;
 95         27: aload_3       
 96         28: invokevirtual #7                  // Method java/util/logging/Logger.info:(Ljava/lang/String;)V
 97         31: aload_3       
 98         32: areturn       
 99       LineNumberTable:
100         line 10: 0
101         line 11: 8
102         line 12: 17
103         line 13: 24
104         line 14: 31
105 
106   public static void main(java.lang.String[]);
107     flags: ACC_PUBLIC, ACC_STATIC
108     Code:
109       stack=2, locals=3, args_size=1
110          0: new           #8                  // class BASE64Util
111          3: dup           
112          4: invokespecial #9                  // Method "<init>":()V
113          7: astore_1      
114          8: ldc           #10                 // String hello world
115         10: astore_2      
116         11: aload_1       
117         12: aload_2       
118         13: invokevirtual #11                 // Method encodeBase64:(Ljava/lang/String;)Ljava/lang/String;
119         16: pop           
120         17: return        
121       LineNumberTable:
122         line 17: 0
123         line 18: 8
124         line 19: 11
125         line 20: 17
126 
127   static {};
128     flags: ACC_STATIC
129     Code:
130       stack=1, locals=0, args_size=0
131          0: ldc_w         #8                  // class BASE64Util
132          3: invokevirtual #12                 // Method java/lang/Class.getName:()Ljava/lang/String;
133          6: invokestatic  #13                 // Method java/util/logging/Logger.getLogger:(Ljava/lang/String;)Ljava/util/logging/Logger;
134          9: putstatic     #6                  // Field log:Ljava/util/logging/Logger;
135         12: return        
136       LineNumberTable:
137         line 7: 0
138 }

 

    4.2.1)

      

      #1 = Methodref          #14.#28        //  java/lang/Object."<init>":()V

      CONSTANT_Fieldref_info, CONSTANT_Methodref_info 和CONSTANT_InterfaceMethodref_info 结构

      字段,方法和接口方法由类似的结构表示: 

      字段:

1 CONSTANT_Fieldref_info {
2     u1 tag;
3     u2 class_index;
4     u2 name_and_type_index;
5 }

      方法:

1 CONSTANT_Methodref_info {
2     u1 tag;
3     u2 class_index;
4     u2 name_and_type_index;
5 }

      接口方法:

1 CONSTANT_InterfaceMethodref_info {
2     u1 tag;
3     u2 class_index;
4     u2 name_and_type_index;
5 }

这些结构各项的说明如下:

      • tag
        CONSTANT_Field_info结构的tag项的值为CONSTANT_Fieldref(9)。CONSTANT_Method_info结构的tag项的值为CONSTANT_Methodref(10)。CONSTANT_InterfaceMethodref_info结构的tag项的值为CONSTANT_InterfaceMethodref(11)。
      • class_index

         class_index项的值必须是对常量池的有效索引,常量池在该索引处的项必须是CONSTANT_Class_info结构,表示一个类或接口,当前字段或者方法是这个类或者接口的成员。

         CONSTANT_Method_info结构的class_index项的类型必须是类(不能是接口)。

         CONSTANT_InterfaceMethodref_info结构的class_index项的类型必须是接口(不能是类)。CONSTANT_Field_info结构的class_index项的类型既可以是类也可以是接口。

      • name_and_type_index

        name_and_type_index项的值必须是对常量池的有效索引,常量池在该索引处的项必须是CONSTANT_NameAndType_info结构,它表示当前字段或者方法的名字和描述符。

        在一个CONSANT_Fieldref_info结构中,给定的描述符必须是字段描述符。而CONSTANT_Methodref_info和CONSTANT_InterfaceMethodref_info中给定的描述符是方法描述符。

        如果一个CONSTANT_Methodref_info结构的方法名以"<"('\u003c')开头,则说明这个方法名是特殊的<init>,即这个方法是实例初始化方法,它的返回类型必须为空。

     

       4.2.2)

        

         #2 = Class              #29            //  sun/misc/BASE64Encoder

         CONSTANT_Class_info 结构
        CONSTANT_Class_info 结构用于表示类或接口,格式如下:
        

1 CONSTANT_Class_info {
2     u1 tag;
3     u2 name_index;
4 }

       CONSTANT_Class_info 结构的项的说明:

      • tag

        CONSTANT_Class_info结构的tag项的值为CONSTANT_Class(7)。

      • name_index          

        name_index项的值,必须是对常量池的一个有效索引。常量池在该索引处的项必须是CONSTANT_Utf8_info结构,代表一个有效的类或接口二进制名称的内部形式。
        因为数组也是由对象表示,所以字节码指令anewarray和multianewarray可以通过常量池中的CONSTANT_Class_info结构来引用类数组。对于这些数组,类的名字就是数组类型的描述符。例如:

        表现二维int数组类型: int[][] 的名字是[[I

        表示一维Thread数组类型Thread[]的名字是:[Ljava/lang/Thread;

        一个有效的数组类型描述符中描述的数组维度必须小于等于255。

     4.2.3) 

     

       #3 = Methodref          #2.#28         //  sun/misc/BASE64Encoder."<init>":()V

     4.2.4) 

       

      #4 = Methodref          #30.#31        //  java/lang/String.getBytes:()[B

     4.2.5) 

      

      #5 = Methodref          #2.#32         //  sun/misc/BASE64Encoder.encodeBuffer:([B)Ljava/lang/String;

    4.2.6) 

        #6 = Fieldref #8.#33 // BASE64Util.log:Ljava/util/logging/Logger;

     4.2.7) 

    #7 = Methodref #34.#35 // java/util/logging/Logger.info:(Ljava/lang/String;)V

    4.2.8) 

    #8 = Class #36 // BASE64Util

    4.2.9) 

    #9 = Methodref #8.#28 // BASE64Util."<init>":()V

   4.2.10)   

   #10 = String             #37            //  hello world

    CONSTANT_String_info 结构
    CONSTANT_String_info 用于表示 java.lang.String 类型的常量对象,格式如下:
    

1 CONSTANT_String_info {
2     u1 tag;
3     u2 string_index;
4 }

     CONSTANT_String_info 结构各项的说明如下:

      • tag        

        CONSTANT_String_info结构的tag值为CONSTANT_String (8)

      • string_index

        string_index项的值必须是对常量池的有效索引,常量池在该索引处的项必须是CONSTANT_Utf8_info结构,表示一组Unicode码点序列,这组Unicode码点序列最终会被初始化一个String对象。
        

   4.2.11)    

       #11 = Methodref #8.#38 // BASE64Util.encodeBase64:(Ljava/lang/String;)Ljava/lang/String;

   4.2.12)   

      #12 = Methodref #39.#40 // java/lang/Class.getName:()Ljava/lang/String;

   4.2.13)  

      #13 = Methodref #34.#41 // java/util/logging/Logger.getLogger:(Ljava/lang/String;)Ljava/util/logging/Logger;

   4.2.14)  

       #14 = Class #42 // java/lang/Object

   4.2.15)   

       #15 = Utf8 log

      CONSTANT_Utf8_info 结构
      

1 CONSTANT_Utf8_info {
2     u1 tag;
3     u2 length;
4     u1 bytes[length];
5 }

    CONSTANT_Utf8_info 结构各项的说明如下:

      • tag

    CONSTANT_Utf8_info 结构的tag项的值为CONSTANT_Utf8(1)。

      • length

    length项的值指明了bytes[]数组的长度(注意,不能等同于当前结构所表示的String对象的长度),CONSTANT_Utf8_info结构中的内容是以length属性确定长度而不是以null作为字符串的终结符。

    bytes[]

    bytes[]是表示字符串值的byte数组,bytes[]数组中每个成员的byte值都不会是0,也不在0xf0和0xff范围内。

  4.2.16) 

    #16 = Utf8 Ljava/util/logging/Logger;

  

  4.2.17) 

    #17 = Utf8 <init>

  4.2.18) 

    #18 = Utf8 ()V

  4.2.19) 

    #19 = Utf8 Code

  4.2.20) 

    #20 = Utf8 LineNumberTable

  4.2.21) 

    #21 = Utf8 encodeBase64

  

  4.2.22) 

    #22 = Utf8 (Ljava/lang/String;)Ljava/lang/String;

  

  4.2.23) 

    #23 = Utf8 main

  4.2.24) 

    #24 = Utf8 ([Ljava/lang/String;)V

  

  4.2.25) 

     #25 = Utf8 <clinit>

   

  4.2.26) 

    #26 = Utf8 SourceFile

  

  4.2.27) 

    #27 = Utf8 BASE64Util.java

  

  4.2.28) 

    #28 = NameAndType #17:#18 // "<init>":()V

    CONSTANT_NameAndType_info 结构
    CONSTANT_NameAndType_info 结构用于表示字段或方法,但是CONSTANT_NameAndType_info结构没有标识出它所属的类或接口,格式如下:

    

1 CONSTANT_NameAndType_info {
2     u1 tag;
3     u2 name_index;
4     u2 descriptor_index;
5 }

CONSTANT_NameAndType_info 结构各项的说明如下:

        • tag

      CONSTANT_NameAndType_info结构的tag项的值为CONSTANT_NameAndType(12)。

        • name_index

      name_index项的值必须是对常量池的有效索引,常量池是在该索引处的项必须是CONSTANT_Utf8_info结构,这个结构要么表示特殊的方法名<init>,要么表示一个有效的字段或方法的非限定名(Unqualified Name)。

        • descriptor_index

      descriptor_index项的值必须是对常量池的有效索引,常量池在该索引处的项必须是CONSTANT_Utf8_info结构,这个结构表示一个有效的字段描述符或方法描述符。

 

    4.2.29) 

     #29 = Utf8 sun/misc/BASE64Encoder

 

    4.2.30) 

      #30 = Class #43 // java/lang/String

    

    4.2.31)  

      #31 = NameAndType #44:#45 // getBytes:()[B

     

    4.2.32) 

      #32 = NameAndType #46:#47 // encodeBuffer:([B)Ljava/lang/String;

    

   4.2.33) 

      #33 = NameAndType #15:#16 // log:Ljava/util/logging/Logger;

    

   4.2.34) 

      #34 = Class #48 // java/util/logging/Logger

  

  4.2.35) 

      #35 = NameAndType #49:#50 // info:(Ljava/lang/String;)V

  

  4.2.36) 

      #36 = Utf8 BASE64Util

  

  4.2.37) 

      #37 = Utf8 hello world

  

  4.2.38) 

     #38 = NameAndType #21:#22 // encodeBase64:(Ljava/lang/String;)Ljava/lang/String;

  

  4.2.39) 

    #39 = Class #51 // java/lang/Class

  

  4.2.40) 

    #40 = NameAndType #52:#53 // getName:()Ljava/lang/String;

  

  4.2.41) 

    #41 = NameAndType #54:#55 // getLogger:(Ljava/lang/String;)Ljava/util/logging/Logger;

  

  4.2.42) 

    #42 = Utf8 java/lang/Object

  

  4.2.43) 

    #43 = Utf8 java/lang/String

 

  4.2.44) 

    #44 = Utf8 getBytes

 

  4.2.45) 

     #45 = Utf8 ()[B

  

  4.2.46) 

    #46 = Utf8 encodeBuffer

  

  4.2.47) 

     #47 = Utf8 ([B)Ljava/lang/String;

  

  4.2.48) 

    #48 = Utf8 java/util/logging/Logger

  

  4.2.49) 

    #49 = Utf8 info

 

  4.2.50)

    #50 = Utf8 (Ljava/lang/String;)V

  

  4.2.51) 

    #51 = Utf8 java/lang/Class

  

  4.2.52) 

     #52 = Utf8 getName

  

  4.2.53) 

    #53 = Utf8 ()Ljava/lang/String;

 

  4.2.54) 

    #54 = Utf8 getLogger

  4.2.55) 

     #55 = Utf8 (Ljava/lang/String;)Ljava/util/logging/Logger;

 

5)  u2 access_flags  

  

标志名 设置后的语义 设置者
ACC_PUBLIC 0x0001 public类型 类和接口
ACC_FINAL 0x0010 类为final 只有类
ACC_SUPER 0x0020 使用新型的invokespecial语义 类和接口
ACC_INTERFACE 0x0200 接口类型,不是类类型 所有的接口,部分类
ACC_ABSTRACT 0X0400 abstract类型 所有的接口,部分类

 

6)  u2 this_class;

 

  #8 = Class #36 // BASE64Util

 

7) u2 super_class;

#14 = Class              #42            //  java/lang/Object

 8) u2 interfaces_count;

 

 

9) u2 interfaces[interfaces_count];

 

10) u2 fields_count;

 

11)  field_info fields[fields_count];

每个字段(Field)都由field_info结构所定义,在同一个Class文件中,不会有两个字段同时具有相同的字段名和描述符。

field_info结构格式如下:

1 field_info {
2     u2 access_flags;
3     u2 name_index;
4     u2 descriptor_index;
5     u2 attributes_count;
6     attribute_info attributes[attributes_count];
7 }

field_info 结构各项说明如下:

  • access_flags

  access_flags项的值是用于定义字段被访问权限和基础属性的掩码标志。

  access_flags的取值范围和相应含义见下表所示。

标记名 说明
ACC_PUBLIC 0x0001 public,表示字段可以从任何包访问。
ACC_PRIVATE 0x0002 private,表示字段仅能该类自身调用。
ACC_PROTECTED 0x0004 protected,表示字段可以被子类调用。
ACC_STATIC 0x0008 static,表示静态字段。
ACC_FINAL 0X0010 final,表示字段定义后值无法修改
ACC_VOLATILE 0X0040 volatile,表示字段是易变的
ACC_TRANSIENT 0x0080 transient,表示字段不会被序列化
ACC_SYNTHETIC 0x1000 表示字段由编译器自动产生
ACC_ENUM 0x4000 enum,表示字段为枚举类型
  • name_index

  name_index项的值必须是对常量池的一个有效索引。常量池在该索引处的项必须是CONSTANT_Utf8_info结构,表示一个有效的字段的非全限定名。

  •  descriptor_index

  descriptor_index项的值必须是对常量池的一个有效索引。常量池在该索引处的项必须是CONSTANT_Utf8_info结构,表示一at个有效的字段段描述符。

  • attribute_count

  attribute_count项的值表示当前字段的附加属性的数量。

  • attributes[]

  attributes表的每一个成员的值都必须是attribute结构,一个字段可以有任意个关联属性。jdk7规范中,attributes表可出现的成员有:

  ConstantValue,Synthetic,Signature,Deprecated,RuntimeVisiableAnnotations和RuntimeInvisibleAnnotations。

  Java虚拟机实现必须正确的识别和读取field_info结构的attributes表中的ConstantValue属性。如果Java虚拟机实现支持版本号为49.0或者更高的Class文件,那么它必须正确的识别和读取这些Class文件中的Signature,RuntimeVisiableAnnotations和RuntimeInvisiableAnnotations结构。

  所有Java虚拟机实现都必须默认忽略field_info结构中的attributes表所不可识别的成员。规范中没有定义的属性不可影响Class文件中的语义,它们只能提供附加描述信息。

  000a = 0080&0020 = ACC_STATIC&ACC_PRIVATE 

  000f= #15 = Utf8 log

  0010=#16 = Utf8 Ljava/util/logging/Logger;

  0000

 

12) u2 methods_count;

 

13) method_info methods[methods_count];

  所有方法(Method),包括实例初始化方法和类初始化方法在内,都由method_info结构所定义。在一个Class文件中,不会有两个方法同时具有相同的方法名和描述符。

  method_info结构格式如下:

method_info {
    u2 access_flags;
    u2 name_index;
    u2 descriptor_index;
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

method_info结构各项的说明如下:

  • access_flags

  access_flags项的值是用于定义当前方法的访问权限和基本属性的掩码标识,access_flags的取值范围和相应含义见下表所示。

标记名 说明
ACC_PUBLIC 0x0001 public,方法可以从包外访问
ACC_PRIVATE 0X0002 private,方法只能本类中访问
ACC_PROTECTED 0X0004 protected,方法在自身和子类中可见
ACC_STATIC 0x0008 static,静态方法
ACC_FINAL 0x0010 final,方法不能被重写
ACC_SYNCHORNIZED 0X0020 synchornized,方法由管程同步
ACC_BRIDGE 0x0040 bridge,方法由编译器产生
ACC_VARARGS 0x0080 标识方法带有变长参数
ACC_NATIVE 0x0100 native,方法引用非java语言的本地方法
ACC_ABSTRACT 0x0400 abstract,方法没有具体实现
ACC_STRICT 0x0800 strictfp,方法使用FP-strict浮点格式  
ACC_SYNTHETIC 0x1000 方法在源文件中不出现,由编译器产生

  ACC_VARARGS标志是用于说明方法在源码层的参数列表是否变长的。如果是变长的,在编译时,方法的ACC_VARARGS标志设置1,其余的方法ACC_VARARGS标志设置为0。

  ACC_BRIDGE标志用于说明这个方法是由编译器生成的桥接方法。桥接方法是JDK1.5引入泛型后,为了使Java的泛型方法生成的字节码和1.5版本前的字节码兼容,由编译器自动生成的方法。

  如果方法设置了ACC_SYNTHETIC标志,则说明这个方法是由编译器生成的并且不会在源代码中出现。

 

  • name_index

  name_index的值必须是对常量池的一个有效索引。常量池在该索引处的项必须是CONSTANT_Utf8_info结构,它要么表示初始化方法的名字(<init>或<clinit>),要么表示一个方法的有效的非全限定名。

 

  • descriptor_index

  descriptor_index项的值必须是对常量池的一个有效索引。常量池在该索引处的项必须是CONSTANT_Utf8_info结构,表示一个有效的方法描述符。

 

  • attributes_count

  attributes_count的项的值表示这个方法的附加属性的数量。

  • attributes[]

  attributes表的每一个成员的值必须是attribute结构,一个方法可以有任意个与之相关的属性。

  本规范所定义的method_info结构中,属性表可出现的成员有:Code,Exceptions , Synthetic ,Signature ,Deprecated ,RuntimeVisiableAnnotations , RuntimeInvisiableAnnotations , RuntimeVisiableParameterAnnotations,RuntimeInvisiableParameterAnnotations和AnnotationDefault结构。

 

  Java虚拟机实现必须正确识别和读取method_info结构中的属性表的Code和Exception属性。如果Java虚拟机实现支持的版本为49.0或更高的Class文件,那么它必须正确识别和读取这些Class文件的Signature , RuntimeVisiableAnnotations , RuntimeInvisiableAnnotations , RuntimeVisiableParameterAnnotations , RuntimeInvisiableParameerAnnotations 和 AnnotationDefault属性。  

  所有Java虚拟机实现必须默认忽略method_info结构中attributes表所不可识别的成员。没有定义的属性不可影响Class文件的语义,它们只能提供附加描述信息。

 

13.1) 

  access_flags (u2)= 0001 = public

  name_index(u2)=0011= #17 = Utf8 <init>

  descriptor_index=0012= #18 = Utf8 ()V

  attributes_count = 0001=1

  13.1.1) attributes[1]

  

  属性(Attribute)在Class文件格式中的ClassFile结构、field_info结构,method_info结构和Code_attribute结构都有使用,所有属性的通用格式如下:

1 attribute_info {
2     u2 attribute_name_index;
3     u4 attribute_length;
4     u1 info[attribute_length];
5 }

  对于任意属性,attribute_name_index必须是对当前Class文件的常量池的有效16位无符号索引。常量池在该索引处的项必须是Constant_Utf8_info结构,表示当前属性的名字。attribute_length的值给出了跟随其后的字节的长度,这个长度不包括attribute_length和attribute_name_index项的6个字节。

  有些属性因Class文件格式所需,已被预先定义好。这些属性在下表中列出,同时,被列出的信息还包括它们首次出现的Class文件版本和Java SE版本号。在规范定义的环境中,也就是已包含这些预定义属性的Class文件中,它们的属性名称被保留,不能再被属性表中的其他自定义属性所使用。

属性名 JavaSE Class文件
ConstantValue 1.0.2 45.3
Code 1.0.2 45.3
StackMapTable 6   50.0
Exceptions 1.0.2 45.3
InnerClass 1.1 45.3
EnclosingMethod 5.0 49.0
Synthetic 1.1 45.3
Signature 5.0 49.0
SourceFile 1.0.2 45.3
SourceDebugExtension 5.0 49.0
LineNumberTable 1.0.2 45.3
LocalVariableTable 1.0.2 45.3
LocalVariableTypeTable 5.0 49.0
Deprecated 1.1 45.3
RuntimeVisiableAnnotations 5.0 49.0
RuntimeInvisiableAnnotations 5.0 49.0
RuntimeVisiableParameterAnnotations 5.0 49.0
RuntimeInvisiableParameterAnnotations 5.0 49.0
AnnotationDefault 5.0 49.0
BootstrapMethods 7 51.0
  •   Java虚拟机实现的Class文件加载器(Class File Reader)必须正确的识别和读取ConstantValue,Code和Exception属性;同样,Java虚拟机也必须能正确的解析它们的语义。
  •   InnerClasses,EnclosingMethod和Synthetic属性必须被Class文件加载器正确的识别并读入,它们用于实现Java平台的类库。
  •   如果Java虚拟机实现支持的Class版本号为49.0或者更高时,它的Class文件加载器必须能正确的识别并读取Class文件中的RuntimeVisiableAnnotations,RuntimeInvisiableAnnotations,RuntimeVisiableParameterAnnotations,RuntimeInvisiableParameterAnnotations和AnnotationDefault属性,它们用于实现Java平台类库。
  • 如果Java虚拟机实现支持的Class文件的版本号为49.0或者更高时,它的Class文件加载器必须正确的识别和读取Class文件中的Signature属性。
  • 如果Java虚拟机实现支持的Class文件的版本号为50.0或者更高时,它的Class文件加载器必须正确的识别和读取StackMapTable属性。
  • 如果Java虚拟机实现支持的Class文件的版本号为51.0或者更高时,它的Class文件加载器必须正确的识别和读取BootstrapMethods属性。
  • 对于剩余的预定义属性的使用不受限制,如果剩余的预定义属性包含虚拟机可识别的信息,Class文件加载器就可以选择使用这些信息,否则可以选择忽略它们。

  u2(attribute_name_index)=0013=#19 = Utf8 Code

  u4(attribute_length)=0000001d=29

 Code属性是一个变长属性,位于method_info结构的属性表。一个Code属性只为唯一一个方法、实例初始化方法或类初始化方法保存Java虚拟机指令以及相关辅助信息。所有Java虚拟机实现都必须能识别Code属性。如果方法被声明为native或者abstract类型,那么对应的method_info结构不能有明确的Code属性,其他情况下,method_info必须有明确的Code属性。

  Code属性的格式如下:

 

Code_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 max_stack;
    u2 max_locals;
    u4 code_length;
    u1 code[code_length];
    u2 exception_table_length;
    { u2 start_pc;
       u2 end_pc;
       u2 handler_pc;
       u2 catch_type;
    } exception_table[exception_table_length];
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}
  • attribute_name_index:

  attribute_name_index项的值必须是对常量池的有效索引,常量池在该索引处的项必须是COSNTANT_Utf8_info结构,表示字符串Code。

  • attribute_length:

  attribute_length项的值表示当前属性的长度,不包括开始的6个字节

  • max_stack

  max_stack项的值给出了当前方法的操作数栈在运行执行的任何时间点的最大深度。

  • max_locals

  max_locals项的值给出了分配在当前方法引用的局部变量表中的局部变量个数,包括调用此方法时,用于传递参数的局部变量。

  long和double型的局部变量的最大索引是max_locals-2,其他类型的局部变量的最大索引是max_locals-1。

  • code_length

  code_length项给出了当前方法的code[]数组的字节数,code_length的值必须大于0,即code[]数组不能为空。

  • code[]

  code[]数组给出了实现当前方法的Java虚拟机字节码。

  code[]数组以按字节寻址的方式读入机器内存,如果code[]数组的第一个字节是按以4字节边界对齐的话,那么tableswitch和lookupswitch指令中所有涉及的32位偏移量也是按4字节长度对齐的。

  • exception_table_length

  exception_table_length的值给出了exception_table[]数组的成员个数。

  • exception_table[]

  exception_table[]数组的每个成员表示code[]数组中的一个异常处理器(ExceptionHandler)。exception_table[]数组中,异常处理顺序是有意义的(不能随意修改)。

  exception_table[]数组包含如下4项:

    •     start_pc和end_pc

  start_pc和end_pc两项的值表明了异常处理器在code[]数组中的有效范围。start_pc必须是当前code[]数组中某一指令的操作码的有效索引,end_pc要么是对当前code[]数组中某一指令的操作码的有效索引,要么等于code_length的值,即当前code[]数组的长度。start_pc的值必须比end_pc小。

  当程序计数器在范围[start_pc,end_pc)内时,异常处理器就将生效。即设x为异常句柄的有效范围内的值,x满足start_pc≤x<end_pc。

  实际上,end_pc的值本身不属于异常处理器的有效范围这点属于Java虚拟机历史上的一个设计缺陷:如果Java虚拟机中的一个方法的code属性的长度刚好是65535个字节,并且是以一个字节长度的指令结束,那么这条指令将不能被异常处理器所处理。不过编译器可能通过限制方法、实例化方法或类初始化方法的code[]数组最大长度为65534,这样可以间接弥补这个Bug。

    •     handler_pc

  handler_pc项表示一个异常处理器的起点,它的值必须同时是一个对当前code[]数组中某一指令的操作码的有效索引

    •     catch_type

  如果catch_type项的值不为0,那么它必须是对常量池的一个有效索引,常量池在该处的索引必须是CONSTANT_Class_info结构,表示当前异常处理器指定需要的捕捉的异常类型。只有当抛出的异常是指定的类或者其子类的实例的时,异常处理器才会被调用。

  如果catch_type项的值如果为0,那么这个异常处理器将会在所有异常抛出时被调用。这可以用于实现finally语句。

  

  •   attributes_count

  attributes_count项的值给出了Code属性中attributes表的成员的个数。

  •   attributes[]

  属性表的每个成员的值必须是attribute结构。一个Code属性可以有任意数量的可选属性与之联系。

  可能出现在Code属性的属性表中的成员只能是LineNumberTable,LocalVariableTable,LocalVariableTypeTable和StackMapTable属性。

  如果一个Java虚拟机实现支持的Class文件版本号为50.0或更高,那么它必须正确的识别和读取Code属性的属性表中出现的StackMapTable属性。

  Java虚拟机实现必须自动忽略Code属性的属性表数组中出现的所有它不能识别的属性。本规范中没有定义的属性不可影响Class文件语义,只能提供附加描述信息。

  

  u2(max_stack)=0001 (表示操作栈在运行时执行的任何时间点的最大深度。)

  u2(max_locals)=0001(在当前方法引用的局部变量表中的局部变量个数)

  u4(code_length)=00000005(当前方法的 code[]数组的字节数)

  code(5)

  2a=aload_0     this将会压如操作数栈顶

  b70001    invokespecial 0001 

          #1 = Methodref #14.#28 // java/lang/Object."<init>":()V

  b1      return 

 

13.2) 

  u2(access_flags) = 0001 = public 

  u2(name_index)=0015= #21 = Utf8               encodeBase64

  u2(descriptor_index)=0016=#22 = Utf8               (Ljava/lang/String;)Ljava/lang/String;

   u2(attributes_count)=0001

  [  

    u2(attribute_name_index)=0013=#19 = Utf8               Code

    u4(attribute_length)=00000049

      [

        u2(max_stack)=0002

        u2(max_locals)=0004

        u4(code_length)=00000021

      ]

  ]

 

 bb 0002 new 0002

      #2 = Class              #29            //  sun/misc/BASE64Encoder

 59 dup (复制栈顶数值并将复制值压入栈顶。)

 b7 0003 invokespecial 0003

    #3 = Methodref          #2.#28         //  sun/misc/BASE64Encoder."<init>":()V

 4d astore_2 

 2c aload_2

 2b aload_1

 b6 0004 invokevirtual 0004

    #4 = Methodref          #30.#31        //  java/lang/String.getBytes:()[B

 b6 0005 invokevirtual 0005

     #5 = Methodref          #2.#32         //  sun/misc/BASE64Encoder.encodeBuffer:([B)Ljava/lang/String; 

 4e astore_3

 b2 0006   getstatic 0006

       #6 = Fieldref           #8.#33         //  BASE64Util.log:Ljava/util/logging/Logger;  

  2b aload_1

  b6 0007 invokespecial 0007

    #7 = Methodref          #34.#35        //  java/util/logging/Logger.info:(Ljava/lang/String;)V 

 

  b2 0006   getstatic 0006

       #6 = Fieldref           #8.#33         //  BASE64Util.log:Ljava/util/logging/Logger;  

 2d aload_3

 

  b6 0007 invokespecial 0007

    #7 = Methodref          #34.#35        //  java/util/logging/Logger.info:(Ljava/lang/String;)V 

 

 2d aload_3

 b0 areturn 

u2(exception_table_length) 0000

u2(attribute_count) 0001 

u2(attribute_name_index)=0014=#20 = Utf8               LineNumberTable

u4(attribue_length)=00000016

LineNumberTable属性

  LineNumberTable属性是可选变长属性,位于Code结构的属性表。它被调试器用于确定源码行号表示的内容在JVM虚拟机的code数组中对应的部分。在Code属性的属性表中,LineNumberTable属性可以按照任意属性出现,此外,多个LineNumberTable属性可以共同表示一个行号在源文件中表示的内容,即LineNumberTable属性不需要与源文件行一一对应。

  LineNumberTable属性格式如下:

1 LineNumberTable_attribute {
2     u2 attribute_name_index;
3     u4 attribute_length;
4     u2 line_number_table_length;
5     { 
6         u2 start_pc;  //start_pc 项的值必须是 code[]数组的一个索引, code[]数组在该索引处的字符
                表示源文件中新的行的起点。 start_pc 项的值必须小于当前 LineNumberTable
                属性所在的 Code 属性的 code_length 项的值。

7 u2 line_number; 8 } line_number_table[line_number_table_length]; 9 }

  u2(line_number_length)=0005 

   (0000,000a)

  (0008,000b)

  (0011,000c)

  (0018,000d)

  (001f,0000e)

 

 78   public java.lang.String encodeBase64(java.lang.String);
 79  flags: ACC_PUBLIC 80  Code: 81 stack=2, locals=4, args_size=2 82 0: new #2 // class sun/misc/BASE64Encoder 83 3: dup 84 4: invokespecial #3 // Method sun/misc/BASE64Encoder."<init>":()V 85 7: astore_2 86 8: aload_2 87 9: aload_1 88 10: invokevirtual #4 // Method java/lang/String.getBytes:()[B 89 13: invokevirtual #5 // Method sun/misc/BASE64Encoder.encodeBuffer:([B)Ljava/lang/String; 90 16: astore_3 91 17: getstatic #6 // Field log:Ljava/util/logging/Logger; 92 20: aload_1 93 21: invokevirtual #7 // Method java/util/logging/Logger.info:(Ljava/lang/String;)V 94 24: getstatic #6 // Field log:Ljava/util/logging/Logger; 95 27: aload_3 96 28: invokevirtual #7 // Method java/util/logging/Logger.info:(Ljava/lang/String;)V 97 31: aload_3 98 32: areturn 99  LineNumberTable: 100 line 10: 0 101 line 11: 8 102 line 12: 17 103 line 13: 24 104 line 14: 31

13.3) 

 

 u2(access_flag)=0009=0008&0001=static&public

 u2(name_index)=0017=#23 = Utf8               main

 u2(descriptor_index)=0018=#24 = Utf8               ([Ljava/lang/String;)V

u2(attributes_count)=0001

  [

    u2(attribute_name_index)= 0013= #19 = Utf8               Code

    u4(attribute_length)=00000036

    u2(max_stacks)=0002

    u2(max_locals)=0003

    u4(code_length)=00000012

      [

        bb 0008 new 0008

          #8 = Class              #36            //  BASE64Util

        59 dup

        b7 0009 invokespecial 0009 

           #9 = Methodref          #8.#28         //  BASE64Util."<init>":()V

        4c astore_1

        12 0a   ldc 0a

          #10 = String             #37            //  hello world

        4d astore_2

        2b aload_1 

        2c aload_2

        b6 000b invokevirtual 000b 

          #11 = Methodref          #8.#38         //  BASE64Util.encodeBase64:(Ljava/lang/String;)Ljava/lang/String;

        57 pop 

        b1 return 

      ]

  ]

u2(exception_table_length) =0000

u2(attribute_length)=0001

u2(attribute_name_index)=0014

   #20 = Utf8               LineNumberTable

u4(attribute_length)=00000012

u2(linenumber_lenth)=0004

  [

    (0000,0011)

    (0008,0012)

    (000b,0013)

    (0011,0014)

  ]

  public static void main(java.lang.String[]);
107  flags: ACC_PUBLIC, ACC_STATIC 108  Code: 109 stack=2, locals=3, args_size=1 110 0: new #8 // class BASE64Util 111 3: dup 112 4: invokespecial #9 // Method "<init>":()V 113 7: astore_1 114 8: ldc #10 // String hello world 115 10: astore_2 116 11: aload_1 117 12: aload_2 118 13: invokevirtual #11 // Method encodeBase64:(Ljava/lang/String;)Ljava/lang/String; 119 16: pop 120 17: return 121  LineNumberTable: 122 line 17: 0 123 line 18: 8 124 line 19: 11 125 line 20: 17 126 

 

13.4) 

 u2(access_flag)=0008=STATIC

u2(name_index)=0019=#25 = Utf8               <clinit>

u2(descriptor_index)=0012=#18 = Utf8               ()V

u2(attribute_coount)=0001

[

  u2(attribute_name_index)=0013=#19 = Utf8               Code

  u3(attribute_length)=000000025

  u2(max_stacks)=0001

  u2(max_locals)=0000

  u4(code_length)=0000000d

  [

    13 0008   ldc_w 0008 (将常量池中的项压入栈)

      #8 = Class              #36            //  BASE64Util

    b6  000c    invokevirtual 000c

      #12 = Methodref          #39.#40        //  java/lang/Class.getName:()Ljava/lang/String;

    b8 000d   invokestatic 000d

      #13 = Methodref          #34.#41        //  java/util/logging/Logger.getLogger:(Ljava/lang/String;)Ljava/util/logging/Logger;

    b3 0006   putstatic 0006

       #6 = Fieldref           #8.#33         //  BASE64Util.log:Ljava/util/logging/Logger;

    b1 return

  ]

  u2(exception_table_length)=0000

  u2(attributes_count)=0001

  [

    u2(attribute_name_index)=0014

      #20 = Utf8               LineNumberTable

    u4(attribute_length)=0000 0006

    u2(line_number_table_length)=0001

    (0000,0007)

  ]

]

  static {};
128  flags: ACC_STATIC 129  Code: 130 stack=1, locals=0, args_size=0 131 0: ldc_w #8 // class BASE64Util 132 3: invokevirtual #12 // Method java/lang/Class.getName:()Ljava/lang/String; 133 6: invokestatic #13 // Method java/util/logging/Logger.getLogger:(Ljava/lang/String;)Ljava/util/logging/Logger; 134 9: putstatic #6 // Field log:Ljava/util/logging/Logger; 135 12: return 136  LineNumberTable: 137 line 7: 0

14)  

  u2(attribute_count) = 0001 

15) 

  u2(attribute_name_index)=001a=#26 = Utf8               SourceFile

  u4(attribute_length)=00000002

  u2(source_file_index)=001b=#27 = Utf8               BASE64Util.java

  SourceFile属性

  SourceFile属性是可选定长字段,位于ClassFile结构的属性表。一个ClassFile结构中的属性表最多只能包含一个SourceFile属性。

  SourceFile属性格式如下:

    

1 SourceFile_attribute {
2     u2 attribute_name_index;
3     u4 attribute_length;
4     u2 sourcefile_index;
5 }

SourceFile_attribute各项的说明如下:

  •   attribute_name_index:

  attribute_name_index 项的值必须是一个对常量池的有效索引。 常量池在该索引处的成员必须是 CONSTANT_Utf8_info结构,表示字符串“ SourceFile”。

  •   sourcefile_index

  sourcefile_index 项的值必须是一个对常量池的有效索引。 常量池在该索引处的成员必须是 CONSTANT_Utf8_info结构,表示一个字符串。

  sourcefile_index 项引用字符串表示被编译的 Class 文件的源文件的名字。不包括源文件所在目录的目录名,也不包括源文件的绝对路径名。
  平台相关(绝对路径名等) 的附加信息必须是运行时解释器( Runtime Interpreter)或开发工具在文件名实际使用时提供。





 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM