Java的class文件结构

http://blog.itpub.net/post/5087/24444/

http://blog.csdn.net/nanjingjiangbiao/article/details/7515545

http://blog.163.com/flywyvern@126/blog/static/19574364200781755259807/


  定义:u1   1个字节为单位的非负值        

         u2   2个字节为单位的非负值
         u3   . . . . . . . .  (其他以此类推 )


    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分别对应结构变化为
        [code]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];
            }[/code]
    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;
          }

          对于constantvalue_index意义如下:
                  long                              CONSTANT_Long  
                  float                             CONSTANT_Float  
                  double                            CONSTANT_Double  
                  int, short, char, byte, boolean   CONSTANT_Integer  
                  String                            CONSTANT_String  

          Constantvalue用于field_info 中,用于描述一个static常量,
          且此时field_info的access_flags应为ACC_STATIC 


      3. Code : attribute_info被替代为:

           Code_attribute {
                    u2 attribute_name_index;
                    u4 attribute_length;
                    u2 max_stack;  //执行此函数时可用的栈的最大深度
                    u2 max_locals; //执行此函数可用到的最大本地变量数目,包括参数。
                                   // 注意:一个long/double相当于2个变量数目.
                    u4 code_length; //本函数用到的代码长度。
                    u1 code[code_length]; //实现本函数的真正字节码
                    u2 exception_table_length;
                    {   u2 start_pc;
                        u2 end_pc; //捕获违例时执行代码数组中的[start_pc, end_pc)部分
                        u2  handler_pc; //现在还不大明白他是干嘛的!!
                        u2  catch_type; //指向constant_pool的索引,对应CONSTANT_Class_info 
                    }exception_table[exception_table_length];
                    u2 attributes_count;
                    attribute_info attributes[attributes_count];
           }

                CONSTANT_Class_info {
                    u1 tag;         //必须为CONSTANT_Class (7)
                    u2 name_index;  //不用我再说了吧?
                 }

           Code属性用于method_info结构中。

      4. Exceptions : attribute_info被替代为:
       
           Exceptions_attribute {
                  u2 attribute_name_index;
                  u4 attribute_length;
                  u2 number_of_exceptions;
                  u2 exception_index_table[number_of_exceptions];
           }

      5. InnerClasses  : attribute_info被替代为:

           InnerClasses_attribute {
                  u2 attribute_name_index;
                  u4 attribute_length;
                  u2 number_of_classes;
                  {  u2 inner_class_info_index;             
                     u2 outer_class_info_index;             
                     u2 inner_name_index;             
                     u2 inner_class_access_flags;             
                  } classes[number_of_classes];
            }

      6. Synthetic : attribute_info被替代为:

           Synthetic_attribute {
                 u2 attribute_name_index;  //不用废话了吧?
                 u4 attribute_length;     //必须为0
           }
          Synthetic用在 field_info、 method_info 中,
          一个没有出现在源程序中的变量必须使用Synthetic标记。

      7. LineNumberTable : attribute_info被替代为:

          LineNumberTable_attribute {
                    u2 attribute_name_index;
                    u4 attribute_length;
                    u2 line_number_table_length;
                    {  u2 start_pc;        //代码数组中的开始处
                       u2 line_number;     //源文件中的行号(对于每一非空行都有这么一项)             
                    } line_number_table[line_number_table_length];
          }
          LineNumberTable用于Code属性中,通常用于调试。


      8. LocalVariableTable : attribute_info被替代为:

              LocalVariableTable_attribute {
                    u2 attribute_name_index;
                    u4 attribute_length;
                    u2 local_variable_table_length;
                    {   u2 start_pc;
                        u2 length; //当解释到代码数组的[start_pc,start_pc+length]
                                   //时变量必须被赋值??
                        u2 name_index;
                        u2 descriptor_index;
                        u2 index;  //到本地变量数组的一个索引
                    } local_variable_table[local_variable_table_length];
              }        

      9. Deprecated : attribute_info被替代为:

              Deprecated_attribute {
                        u2 attribute_name_index;
                    u4 attribute_length;   //必须为0
              }


      当然你也可以定义自己的属性,但要你自己的编译器和虚拟机实现。JVM将忽略自己不认可的属性。

来实践一下吧!
编写一个最简单的程序:
class Test 
{
        public static void main(String[] args) 
        {
                System.out.println("Hello World!");
        }
}

c:work>javac Test.java

c:work>filedump Test.class

File Dump V0.3 Beta by cloud (safesuite@363.net).

01:00    ca fe ba be 00 03 00 2d 00 1d 0a 00 06 00 0f 09   .......-........
01:01    00 10 00 11 08 00 12 0a 00 13 00 14 07 00 15 07   ................
01:02    00 16 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29   .....<init>...()
01:03    56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e   V...Code...LineN
01:04    75 6d 62 65 72 54 61 62 6c 65 01 00 04 6d 61 69   umberTable...mai
01:05    6e 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67   n...([Ljava/lang
01:06    2f 53 74 72 69 6e 67 3b 29 56 01 00 0a 53 6f 75   /String;)V...Sou
01:07    72 63 65 46 69 6c 65 01 00 09 54 65 73 74 2e 6a   rceFile...Test.j
>d
02:00    61 76 61 0c 00 07 00 08 07 00 17 0c 00 18 00 19   ava.............
02:01    01 00 0c 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 07   ...Hello World!.
02:02    00 1a 0c 00 1b 00 1c 01 00 04 54 65 73 74 01 00   ..........Test..
02:03    10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63   .java/lang/Objec
02:04    74 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79   t...java/lang/Sy
02:05    73 74 65 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61   stem...out...Lja
02:06    76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61   va/io/PrintStrea
02:07    6d 3b 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72 69   m;...java/io/Pri
>d
03:00    6e 74 53 74 72 65 61 6d 01 00 07 70 72 69 6e 74   ntStream...print
03:01    6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e 67   ln...(Ljava/lang
03:02    2f 53 74 72 69 6e 67 3b 29 56 00 20 00 05 00 06   /String;)V. ....
03:03    00 00 00 00 00 02 00 00 00 07 00 08 00 01 00 09   ................
03:04    00 00 00 1d 00 01 00 01 00 00 00 05 2a b7 00 01   ............*...
03:05    b1 00 00 00 01 00 0a 00 00 00 06 00 01 00 00 00   ................
03:06    01 00 09 00 0b 00 0c 00 01 00 09 00 00 00 25 00   ..............%.
03:07    02 00 01 00 00 00 09 b2 00 02 12 03 b6 00 04 b1   ................
>d
04:00    00 00 00 01 00 0a 00 00 00 0a 00 02 00 00 00 05   ................
04:01    00 08 00 06 00 01 00 0d 00 00 00 02 00 0e         ..............
>

解读一下:

ca fe ba be     magic
00 03 00 2d     次主版本号,换算一下:   45.3 (注意,不是高字节在前,别犯职业病!)
00 1d           constant_pool元素个数加一  :  29  那么constant_pool就是[1-28]
constant_pool: 1-28

1.  0a 00 06 00 0f  
                0x0a :CONSTANT_InterfaceMethodref  0x06 :class index  0x0f :name-type-index
2.  09 00 10 00 11
                0x09 : CONSTANT_Fieldref             0x10:  . . .       0x11 : . . . .
3.  08 00 12     0x08 : CONSTANT_String    0x12 : string_index
4.  0a 00 13 00 14     0x0a同于1.
5.  07 00 15     0x07 : CONSTANT_Class     0x15 : name_index
6.  07 00 16   
7.  01 00 06 3c 69 6e 69 74 3e 01  ...<init>    
                0x01   CONSTANT_Utf8     0x06  : string length   "<init>" : 构造函数
8.  01 00 03 28 29 56   ...()V   函数,无参数
  0x01   . . . . . .       0x03  : . . . .         "()V"    :  . . .
9.  01 00 04 43 6f 64 65    ...Code
10. 01 00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65  ...LineNumberTable
11. 01 00 04 6d 61 69 6e    ...main
12. 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56 
           ...([Ljava/lang/String;)V   函数,参数为String[]类型
13. 01 00 0a 53 6f 75 72 63 65 46 69 6c 65   ...SourceFile
14. 01 00 09 54 65 73 74 2e 6a 61 76 61      ...Test.java
15. 0c 00 07 00 08         0x0c:CONSTANT_NameAndType  07 : name-index 08:name-type-index
16. 07 00 17
17. 0c 00 18 00 19
18. 01 00 0c 48 65 6c 6c 6f 20 57 6f 72 6c 64 21  ...Hello World!
19. 07 00 1a
20. 0c 00 1b 00 1c
21. 01 00 04 54 65 73 74   ...Test
22. 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74   ...java/lang/Object
23. 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 65 6d   ...java/lang/System
24. 01 00 03 6f 75 74    ...out
25. 01 00 15 4c 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d 3b
       ...Ljava/io/PrintStream;
26. 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d...java/io/PrintStream
27. 01 00 07 70 72 69 6e 74 6c 6e   ...println
28. 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56
       ...(Ljava/lang/String;)V


00 20    access_flags   
00 05    this_class
00 06    super_class
00 00    interfaces_count
00 00    fields_count
00 02    methods_count

methods[2]:

method_info {
    u2 access_flags;
    u2 name_index; 
    u2 descriptor_index;
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}
0.   00 00     access_flags;
     00 07     name_index;     看看constant_pool的第7项: <init>  表明当前描述构造函数
     00 08     descriptor_index;
     00 01     attributes_count;
     00 09     attribute_name_index   0x09 看看constant_pool的第9项,简单明了Code !! 
     00 00 00 1d  attribute_length   = 29
     00 01     max_stack
     00 01     max_locals
     00 00 00 05  code_length
     2a b7 00 01 b1       JVM定义的操作码代码段数组
     00 00    exception_table_length
     00 01    attributes_count     一个,接下来是attribute_info结构
     00 0a    attribute_name_index  看看constant_pool的第10项: LineNumberTable(显然调试用)
     00 00 00 06  attribute_length
     00 01    line_number_table_length
     00 00    start_pc
     00 01    line_number

1.   00 09    access_flags   PUBLIC & STATIC
     00 0b    name_index;                   表明当前描述main函数
     00 0c    descriptor_index;   ...([Ljava/lang/String;)V
     00 01    attributes_count;
     00 09    attribute_name_index   Code
     00 00 00 25    attribute_length   = 37
     00 02    max_stack
     00 01    max_locals 
     00 00 00 09   code_length
     b2 00 02 12 03 b6 00 04 b1    代码数组  codeArray1[0-8]
     00 00    exception_table_length
     00 01    attributes_count    接下来是attribute_info结构
     00 0a    attribute_name_index  LineNumberTable
     00 00 00 0a  attribute_length
     00 02    line_number_table_length
     00 00    start_pc
     00 05    line_number
     00 08    start_pc     : codeArray1[8] = 0xb1 -->  return
     00 06    line_number  第6行源程序为  }
     
     
00 01     attributes_count
00 0d     attribute_name_index   属性为SourceFile
00 00 00 02  attribute_length
00 0e     sourcefile_index    constant_pool[0x0e] --- >  "Test.java"


接下来我们看看main()函数对应的代码:

b2 00 02 12 03 b6 00 04 b1

0xb2  0x00  0x02 : getstatic #2
         看看constant_pool[0x02] :09 00 10 00 11
                0x09 : CONSTANT_Fieldref         0x10:  class index   0x11 :name-type-index
   constant_pool[0x10]:  --> constant_pool[0x17]  : java/lang/System
   constant_pool[0x11]:    0x18 : class index   0x19 :name-type-index
            constant_pool[0x18] : out
     constant_pool[0x19] : Ljava/io/PrintStream

       即 System.out 为 java.io.PrintStream 类型
   
      

0x12  0x03  : ldc #3
          看看 constant_pool[3] : 08 00 12     0x08 : CONSTANT_String    0x12 : string_index
                 指向一个字符串  constant_pool[0x12]: "Hello World!"
          故该指令加载了字符串索引到本地栈
0xb6  0x00  0x04: invokevirtual #4 
                        ------->到constant_pool查查 0x13  :class   0x14 :name-type
                          看看constant_pool[0x13]:java/io/PrintStream
            constant_pool[20] :-->  00 1b 00 1c
            constant_pool[0x1b]:println
            . . . .            :(Ljava/lang/String;)V

       故该指令调用了 java.io.PrintStream.println(java.lang.String)
           而参数则为 ldc #3 加载的 "Hello World!"
0xb1  : return


关于opcode的更多信息参见  http://mrl.nyu.edu/~meyer/jvmref/  ; 和JVM文档
转自  http://watercloud.nease.net/



java class 文件结构的分析  

代码:

public class test
{
 public static void main(String arg[])
 {
  System.out.Println("Hello world");
 }
}
生成class文件
test Class File Structor:
Magic Number----0XCafeBabe 四个字节
Minor Version---0X0000     两个字节 最小版本号
Max   Version---0X002e     两个字节 最大版本号 
--------------------------------------------------------------------------------
以上为说明本文件是class 文件及版本 一下是正题
--------------------------------------------------------------------------------
constant_pool_count 0x001d  常量池的大小为28个
--------------------------------------------------------------------------------
常量池开始
--------------------------------------------------------------------------------
注:除01标志(utf-8 表外其余后面的Hex 均为索引)
1  0a 00 06 00 0f   方法常量   0x0006 java/lang/Object           0x000f <init>    ()V 
2  09 00 10 00 11   字段常量   0x0010 java/lang/System           0x0011 out       Ljava/lang/io/PrintStream
3  08 00 12        字符串常量 0x0012 hello wold
4  0a 00 13 00 14   方法常量   0x0013 java/lang/io/PringtStream  0x0014 PrintIn   ([Ljava/lang/String;)V
5  07 00 15      类常量     0x0015 test2
6  07 00 16         类常量     0x0016 java/lang/Object
7  01 00 06  ----   <init>
8  01 00 03  ----   ()v
9  01 00 04  ----   code
0a 01 00 0F  ----   LineNumberTable
0b 01 00 04  ----   main
0c 01 00 16  ----   ([Ljava/lang/String;)v
0d 01 00 0A  ----   sourcefile
0e 01 00 0A  ----   test2.java
0f 0c 00 07 00 08   符号引用  0x0007 <init>                      0x0008 ()v
10 07 00 17         类常量    0x0017 java/lang/System
11 0c 00 18 00 19   符号引用  0x0018 out                         0x0019 Ljava/lang/io/PrintStream;
12 01 00 0B  ----   hello wold     
13 07 00 1A  ----   类常量    0x001a java/lang/io/PringtStream
14 0c 00 1b 00 1c   符号引用  0x001b PrintIn                     0x001c ([Ljava/lang/String;)V
15 01 00 05  ----   test2
16 01 00 10  ----   java/lang/Object
17 01 00 10  ----   java/lang/System
18 01 00 03  ----   out
19 01 00 15  ----   Ljava/lang/io/PrintStream;
1a 01 00 13  ----   java/lang/io/PringtStream
1b 01 00 07  ----   PrintIn
1c 01 00 15  ----   ([Ljava/lang/String;)V
到此常量池结束
对于常量池的总结:
由上面的二进制代码以及常量池类型表的分析
我认为常量池中有三种类型的的常量
一种是tag(类型) 型的常量 
如 类常量      type  内容 
   字段常量    type  类   内容
   方法常量    type  类   
   接口方法常量 
这些常量的目的是为了与语言接口 
一种是内容型常量
如 utf-8 常量 integer float long double string 等常量
这些常量的目的是为了表达内容
一种是过渡型常量
就是name-type型常量 这种常量的目的就是为了过渡的表示如果无法使用
一个内容常量表示的使用这个常量进行过度。如图
由此的到class 文件常量池的设计原则是
一 所有的类元数据内容都放在utf-8以及其他类型int float 中
二 不同的类元数据类型分别放在 类常量 字段常量 方法常量当中---即类型与内容
分开易于扩展
三 允许嵌套表示 如name-type型
所以常量池的组织的思路类似于XML的组织思路。在.net中就直接使用了XML来描述
元数据
以上为常量池
----------------------------------------------------------------------------
1d 00 21  access_flags 可访问性 acc_Super
1e 00 05  test2 
1f 00 06  java/lang/Object
20 00 00  interface count=0
21 00 00  field     count=0 
22 00 02  method    count=2

/
方法一 init方法

 00 01 00 07 00 08 00 01  方法信息 0x0001 acc_public 0x0007 <init> 0x0008 
                            ()v 0x0001 one atrribute 
   00 09 00 00 00 1D        0x0009 code 0x0000001d code属性 29个字节
   00 01 00 01 00 00 00 05  0x0001 最大栈 0x0001 最大局部变量 0x0000005 code
                  数5个字节
   2a b7 00 01 b1           0x2a aload_0       得到局部变量0位置的对象引用    
                            0xb7 invokespecial 调用制定类的方法
                            0x0001 java/lang/object.init()v
                            0xb1   return
  00 00                     0x0000 exception count=0
  00 01                     0x0001 attribute count=1
  00 0a 00 00 00 06         0x000a     LineNumberTable
                            0x00000006 LineNumberTable属性字节码长6个字节
  00 01 00 00 00 01         0x0001     LineNumbertable 数一个
         0x0000     star_pc 开始0
         0x0001     line_number 开1行
 
 ///
 方法二 main方法
 //
00 09 00 0b 00 0c 00 01  方法信息 0x0009  public&static
                         0x000b   main
                         0x000c   ([Ljava/lang/String;)v
                         0x0001   属性一
00 09 00 00 00 25        0x0009   code属性
                         0x00000025 code属性长25字节                         
00 02 00 01 00 09        0x0002   最大栈数2 
    0x0001   最大局部变量数1 
    0x0009   code长9个字节
b2 00 02 12 03 b6 00 04 b1 
      0xb2 00 02  getstatic #2
      得到java/lang/system.out 字段 字段类型 Ljava/lang/io/PrintStream
      0x12 03 ldc #03  
      将hello world 入栈
      0xb6 00 04  invokevirtual #04
      调用java/lang/io/PrintStream.Printin 方法
      0xb1 return 
00 00                    0x0000 exception count=0
00 01                    0x0001 属性数1 个
00 0a 00 00 00 0a        0x000a LineNumberTable
    0x0000000a   LineNumberTable属性字节码长10个字节
00 02 00 00 00 05 00 08 00 06
                         0x0002 有两个LineNumberTable
                         0x0000  star_p 00
                         0x0005  line_number 05行
                         0x0008  star_p 08
                         0x0006  line_number 06行
到此方法信息完毕
---------------------------------------------------------------------------------
00 01                   0x0001 表示class有一个属性
00 0d 00 00 00 02 00 0e 0x000d sourcefile 属性
   0x00000002 长两个字节
   0x000e test2.java
到此class文件结束   
--------------------------------------------------------------------------------

总结: 
通过对上述class 文件的研究我做了个总结
个人认为设计class 文件的原则如下: 
其一 class 文件是按节点方式组织的
     每个节点包括两个部分一个是对自身的描述 
           一个属性
           
其二 class 文件按层状方式将节点组织起来
其三 全局元数数据 使用常量池描述


节点:
    class 文件的节点有
    class 节点 
             self-describe
             ------------
              magicnumber
              minor_version
              max_version 
              this_class
              super_class
              -----------
              Attribute
              -----------
              sourcefile *
              innerclass *             
    field 节点
              self-describe
             ------------
              access_flags
              name_index
              describe_index
              -----------
              Attribute
              -----------
              ConstantValue*
              Deprecated * 
              Synthetic *
   Method 节点
              self-describe
             ------------
              access_flags
              name_index
              describe_index
              -----------
              Attribute
              -----------
              Code*
              Deprecated * 
              Synthetic * 
              Exception *
    code  节点
             self-describe
             ------------
              max_stack
              max_locals
              code 
              -----------
              Attribute
              -----------
              LineNumberTable*
              LocalVariableTable * 
              Excepion * 
   基本上class文件就是由上述的节点及属性以及节点大小构成
   而且节点嵌套要满足如下层次关系
   如下是节点关系图
   class 节点 
         interface 节点
         field     节点
         method    节点    
           code 节点 
              LineNumberTable 属性
  注:* 表示可选
      节点属性的区别 基本上是节点可以再包含属性,属性只有字描述
      
  延伸: 
       据我现在所知。net 的PE文件 格式如下
       PE头 
       CLR头
       元数据
       IL码
 其于CLass 文件从可读性而言应该是进步了,
 其一 其明确的将数据与数据描述分离出来 形成元数据而没有像 class 文件中的这样
 混淆防止 有力于数据扩展
 其二 有用于对运行环境的说明的PE头 CLR头 等 
 对于PE文件格式分析我想在手头有材料和精力的时候再写
 我估计PE格式的方式是
 将Class,field,Method,interface code以及的自我描述信息都提取出来作为XML 的节点
 然后将属性分配到各个节点当中
 然后将Code 部分的信息提取出来  
 以上对于Class文件格式的分析只是一个就事论事的分析,期望能过段时间能有提炼性的分析
 
 问题:
      为什么要按照这样的方式设计class 文件呢!?
      虚拟机时如何解析这个Class文件 并且将它放当内存中的呢以及如何放的呢?
     

参考文献:

      http://www.matrix.org.cn/resource/article/0/21.html
      http://mrl.nyu.edu/~meyer/jvmref/      
      《深入java 虚拟机》


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值