java class文件詳解

Java Class文件結構信息:


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];             //屬性表

}

1  代碼實例:


                地址:   https://github.com/pantherproject/jvm-practice/tree/master/src/main/java/com/panther/jvm



用二進制打開文件:


 hexdump -C Sub.class 
00000000  ca fe ba be 00 00 00 34  00 3b 0a 00 0a 00 28 09  |.......4.;....(.|
00000010  00 09 00 29 09 00 09 00  2a 09 00 09 00 2b 09 00  |...)....*....+..|
00000020  2c 00 2d 08 00 2e 0a 00  2f 00 30 08 00 31 07 00  |,.-...../.0..1..|
00000030  32 07 00 33 07 00 34 07  00 35 01 00 06 73 75 62  |2..3..4..5...sub|
00000040  49 6e 74 01 00 01 49 01  00 09 73 75 62 53 74 72  |Int...I...subStr|
00000050  69 6e 67 01 00 12 4c 6a  61 76 61 2f 6c 61 6e 67  |ing...Ljava/lang|
00000060  2f 53 74 72 69 6e 67 3b  01 00 09 73 75 62 4f 62  |/String;...subOb|
00000070  6a 65 63 74 01 00 12 4c  6a 61 76 61 2f 6c 61 6e  |ject...Ljava/lan|
00000080  67 2f 4f 62 6a 65 63 74  3b 01 00 06 3c 69 6e 69  |g/Object;...<ini|
00000090  74 3e 01 00 03 28 29 56  01 00 04 43 6f 64 65 01  |t>...()V...Code.|
000000a0  00 0f 4c 69 6e 65 4e 75  6d 62 65 72 54 61 62 6c  |..LineNumberTabl|
000000b0  65 01 00 09 67 65 74 53  75 62 49 6e 74 01 00 03  |e...getSubInt...|
000000c0  28 29 49 01 00 09 73 65  74 53 75 62 49 6e 74 01  |()I...setSubInt.|
000000d0  00 04 28 49 29 56 01 00  0c 67 65 74 53 75 62 53  |..(I)V...getSubS|
000000e0  74 72 69 6e 67 01 00 14  28 29 4c 6a 61 76 61 2f  |tring...()Ljava/|
000000f0  6c 61 6e 67 2f 53 74 72  69 6e 67 3b 01 00 0c 73  |lang/String;...s|
00000100  65 74 53 75 62 53 74 72  69 6e 67 01 00 15 28 4c  |etSubString...(L|
00000110  6a 61 76 61 2f 6c 61 6e  67 2f 53 74 72 69 6e 67  |java/lang/String|
00000120  3b 29 56 01 00 0c 67 65  74 53 75 62 4f 62 6a 65  |;)V...getSubObje|
00000130  63 74 01 00 14 28 29 4c  6a 61 76 61 2f 6c 61 6e  |ct...()Ljava/lan|
00000140  67 2f 4f 62 6a 65 63 74  3b 01 00 0c 73 65 74 53  |g/Object;...setS|
00000150  75 62 4f 62 6a 65 63 74  01 00 15 28 4c 6a 61 76  |ubObject...(Ljav|
00000160  61 2f 6c 61 6e 67 2f 4f  62 6a 65 63 74 3b 29 56  |a/lang/Object;)V|
00000170  01 00 06 69 6e 74 65 72  43 01 00 06 69 6e 74 65  |...interC...inte|
00000180  72 42 01 00 15 28 49 29  4c 6a 61 76 61 2f 6c 61  |rB...(I)Ljava/la|
00000190  6e 67 2f 53 74 72 69 6e  67 3b 01 00 0a 53 6f 75  |ng/String;...Sou|
000001a0  72 63 65 46 69 6c 65 01  00 08 53 75 62 2e 6a 61  |rceFile...Sub.ja|
000001b0  76 61 0c 00 13 00 14 0c  00 0d 00 0e 0c 00 0f 00  |va..............|
000001c0  10 0c 00 11 00 12 07 00  36 0c 00 37 00 38 01 00  |........6..7.8..|
000001d0  11 74 68 65 20 69 6e 74  65 72 43 20 69 6e 20 53  |.the interC in S|
000001e0  75 62 07 00 39 0c 00 3a  00 1e 01 00 11 74 68 65  |ub..9..:.....the|
000001f0  20 69 6e 74 65 72 42 20  69 6e 20 53 75 62 01 00  | interB in Sub..|
00000200  13 63 6f 6d 2f 70 61 6e  74 68 65 72 2f 6a 76 6d  |.com/panther/jvm|
00000210  2f 53 75 62 01 00 14 63  6f 6d 2f 70 61 6e 74 68  |/Sub...com/panth|
00000220  65 72 2f 6a 76 6d 2f 42  61 73 65 01 00 16 63 6f  |er/jvm/Base...co|
00000230  6d 2f 70 61 6e 74 68 65  72 2f 6a 76 6d 2f 49 6e  |m/panther/jvm/In|
00000240  74 65 72 42 01 00 16 63  6f 6d 2f 70 61 6e 74 68  |terB...com/panth|
00000250  65 72 2f 6a 76 6d 2f 49  6e 74 65 72 43 01 00 10  |er/jvm/InterC...|
00000260  6a 61 76 61 2f 6c 61 6e  67 2f 53 79 73 74 65 6d  |java/lang/System|
00000270  01 00 03 6f 75 74 01 00  15 4c 6a 61 76 61 2f 69  |...out...Ljava/i|
00000280  6f 2f 50 72 69 6e 74 53  74 72 65 61 6d 3b 01 00  |o/PrintStream;..|
00000290  13 6a 61 76 61 2f 69 6f  2f 50 72 69 6e 74 53 74  |.java/io/PrintSt|
000002a0  72 65 61 6d 01 00 07 70  72 69 6e 74 6c 6e 00 21  |ream...println.!|
000002b0  00 09 00 0a 00 02 00 0b  00 0c 00 03 00 02 00 0d  |................|
000002c0  00 0e 00 00 00 0a 00 0f  00 10 00 00 00 0a 00 11  |................|
000002d0  00 12 00 00 00 09 00 01  00 13 00 14 00 01 00 15  |................|
000002e0  00 00 00 1d 00 01 00 01  00 00 00 05 2a b7 00 01  |............*...|
000002f0  b1 00 00 00 01 00 16 00  00 00 06 00 01 00 00 00  |................|
00000300  06 00 01 00 17 00 18 00  01 00 15 00 00 00 1d 00  |................|
00000310  01 00 01 00 00 00 05 2a  b4 00 02 ac 00 00 00 01  |.......*........|
00000320  00 16 00 00 00 06 00 01  00 00 00 0f 00 01 00 19  |................|
00000330  00 1a 00 01 00 15 00 00  00 22 00 02 00 02 00 00  |........."......|
00000340  00 06 2a 1b b5 00 02 b1  00 00 00 01 00 16 00 00  |..*.............|
00000350  00 0a 00 02 00 00 00 13  00 05 00 14 00 09 00 1b  |................|
00000360  00 1c 00 01 00 15 00 00  00 1c 00 01 00 00 00 00  |................|
00000370  00 04 b2 00 03 b0 00 00  00 01 00 16 00 00 00 06  |................|
00000380  00 01 00 00 00 17 00 09  00 1d 00 1e 00 01 00 15  |................|
00000390  00 00 00 21 00 01 00 01  00 00 00 05 2a b3 00 03  |...!........*...|
000003a0  b1 00 00 00 01 00 16 00  00 00 0a 00 02 00 00 00  |................|
000003b0  1b 00 04 00 1c 00 09 00  1f 00 20 00 01 00 15 00  |.......... .....|
000003c0  00 00 1c 00 01 00 00 00  00 00 04 b2 00 04 b0 00  |................|
000003d0  00 00 01 00 16 00 00 00  06 00 01 00 00 00 1f 00  |................|
000003e0  09 00 21 00 22 00 01 00  15 00 00 00 21 00 01 00  |..!.".......!...|
000003f0  01 00 00 00 05 2a b3 00  04 b1 00 00 00 01 00 16  |.....*..........|
00000400  00 00 00 0a 00 02 00 00  00 23 00 04 00 24 00 01  |.........#...$..|
00000410  00 23 00 14 00 01 00 15  00 00 00 25 00 02 00 01  |.#.........%....|
00000420  00 00 00 09 b2 00 05 12  06 b6 00 07 b1 00 00 00  |................|
00000430  01 00 16 00 00 00 0a 00  02 00 00 00 28 00 08 00  |............(...|
00000440  29 00 01 00 24 00 25 00  01 00 15 00 00 00 1b 00  |)...$.%.........|
00000450  01 00 02 00 00 00 03 12  08 b0 00 00 00 01 00 16  |................|
00000460  00 00 00 06 00 01 00 00  00 2d 00 01 00 26 00 00  |.........-...&..|
00000470  00 02 00 27                                       |...'|
00000474




2. 魔數

作用:確定該文件是否是虛擬機可接受的class文件。java的魔數統一爲 0xCAFEBABE (來源於一款咖啡)。

區域:文件第0~3字節。



3. 版本號


作用:表示class文件的版本,由minorversion和majorversion組成。

區域:文件第4~7字節。


51代表,jdk爲1.7.0

需要注意的是java版本號是從45開始的,大版本發佈,主版本號+1.高版本的jdk能向下兼容以前版本的class文件,但不兼容以後版本的class文件



4. 常量池

常量池的大小是不固定的,根據你的類中的常量的多少而定,所以在常量池的入口,放置了一個u2類型的表示常量池中常量個數的常量池容量計數器。計數器從1開始,第0位有特殊含義,表示指向常量池的索引值數據不引用任何一個常量池項目。池中的數據項就像數組一樣是通過索引訪問的。


我們可以清楚的看到,我們常量池中有63-1=62個常量。這些常量是什麼呢?

要存放字面量Literal和符號引用Symbolic References。

字面量可能是文本字符串,或final的常量值。
符號引用包括以下:

  • 類或接口全限定名 Full Qualified Name
  • 字段名稱和描述符 Descriptor
  • 方法名稱和描述符


我們使用反編譯工具查看一下:

javap -v Sub.class 
Classfile /opt/soft/project/54/jvm-practice/src/main/java/com/panther/jvm/Sub.class
  Last modified 2017-8-23; size 1140 bytes
  MD5 checksum e07ec896433041cc874ab7adabd1c7ac
  Compiled from "Sub.java"
public class com.panther.jvm.Sub extends com.panther.jvm.Base implements com.panther.jvm.InterB,com.panther.jvm.InterC
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #10.#40        // com/panther/jvm/Base."<init>":()V
   #2 = Fieldref           #9.#41         // com/panther/jvm/Sub.subInt:I
   #3 = Fieldref           #9.#42         // com/panther/jvm/Sub.subString:Ljava/lang/String;
   #4 = Fieldref           #9.#43         // com/panther/jvm/Sub.subObject:Ljava/lang/Object;
   #5 = Fieldref           #44.#45        // java/lang/System.out:Ljava/io/PrintStream;
   #6 = String             #46            // the interC in Sub
   #7 = Methodref          #47.#48        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #8 = String             #49            // the interB in Sub
   #9 = Class              #50            // com/panther/jvm/Sub
  #10 = Class              #51            // com/panther/jvm/Base
  #11 = Class              #52            // com/panther/jvm/InterB
  #12 = Class              #53            // com/panther/jvm/InterC
  #13 = Utf8               subInt
  #14 = Utf8               I
  #15 = Utf8               subString
  #16 = Utf8               Ljava/lang/String;
  #17 = Utf8               subObject
  #18 = Utf8               Ljava/lang/Object;
  #19 = Utf8               <init>
  #20 = Utf8               ()V
  #21 = Utf8               Code
  #22 = Utf8               LineNumberTable
  #23 = Utf8               getSubInt
  #24 = Utf8               ()I
  #25 = Utf8               setSubInt
  #26 = Utf8               (I)V
  #27 = Utf8               getSubString
  #28 = Utf8               ()Ljava/lang/String;
  #29 = Utf8               setSubString
  #30 = Utf8               (Ljava/lang/String;)V
  #31 = Utf8               getSubObject
  #32 = Utf8               ()Ljava/lang/Object;
  #33 = Utf8               setSubObject
  #34 = Utf8               (Ljava/lang/Object;)V
  #35 = Utf8               interC
  #36 = Utf8               interB
  #37 = Utf8               (I)Ljava/lang/String;
  #38 = Utf8               SourceFile
  #39 = Utf8               Sub.java
  #40 = NameAndType        #19:#20        // "<init>":()V
  #41 = NameAndType        #13:#14        // subInt:I
  #42 = NameAndType        #15:#16        // subString:Ljava/lang/String;
  #43 = NameAndType        #17:#18        // subObject:Ljava/lang/Object;
  #44 = Class              #54            // java/lang/System
  #45 = NameAndType        #55:#56        // out:Ljava/io/PrintStream;
  #46 = Utf8               the interC in Sub
  #47 = Class              #57            // java/io/PrintStream
  #48 = NameAndType        #58:#30        // println:(Ljava/lang/String;)V
  #49 = Utf8               the interB in Sub
  #50 = Utf8               com/panther/jvm/Sub
  #51 = Utf8               com/panther/jvm/Base
  #52 = Utf8               com/panther/jvm/InterB
  #53 = Utf8               com/panther/jvm/InterC
  #54 = Utf8               java/lang/System
  #55 = Utf8               out
  #56 = Utf8               Ljava/io/PrintStream;
  #57 = Utf8               java/io/PrintStream
  #58 = Utf8               println
{
  public com.panther.jvm.Sub();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method com/panther/jvm/Base."<init>":()V
         4: return
      LineNumberTable:
        line 6: 0

  public int getSubInt();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field subInt:I
         4: ireturn
      LineNumberTable:
        line 15: 0

  public void setSubInt(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: iload_1
         2: putfield      #2                  // Field subInt:I
         5: return
      LineNumberTable:
        line 19: 0
        line 20: 5

  public static java.lang.String getSubString();
    descriptor: ()Ljava/lang/String;
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: getstatic     #3                  // Field subString:Ljava/lang/String;
         3: areturn
      LineNumberTable:
        line 23: 0

  public static void setSubString(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: putstatic     #3                  // Field subString:Ljava/lang/String;
         4: return
      LineNumberTable:
        line 27: 0
        line 28: 4

  public static java.lang.Object getSubObject();
    descriptor: ()Ljava/lang/Object;
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: getstatic     #4                  // Field subObject:Ljava/lang/Object;
         3: areturn
      LineNumberTable:
        line 31: 0

  public static void setSubObject(java.lang.Object);
    descriptor: (Ljava/lang/Object;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: putstatic     #4                  // Field subObject:Ljava/lang/Object;
         4: return
      LineNumberTable:
        line 35: 0
        line 36: 4

  public void interC();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #6                  // String the interC in Sub
         5: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 40: 0
        line 41: 8

  public java.lang.String interB(int);
    descriptor: (I)Ljava/lang/String;
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=2, args_size=2
         0: ldc           #8                  // String the interB in Sub
         2: areturn
      LineNumberTable:
        line 45: 0
}
SourceFile: "Sub.java"

常量池中的項目類型如下:

  • CONSTANT_Utf8_info      tag標誌位爲1,   UTF-8編碼的字符串
  • CONSTANT_Integer_info  tag標誌位爲3, 整形字面量
  • CONSTANT_Float_info     tag標誌位爲4, 浮點型字面量
  • CONSTANT_Long_info     tag標誌位爲5, 長整形字面量
  • CONSTANT_Double_info  tag標誌位爲6, 雙精度字面量
  • CONSTANT_Class_info    tag標誌位爲7, 類或接口的符號引用
  • CONSTANT_String_info    tag標誌位爲8,字符串類型的字面量
  • CONSTANT_Fieldref_info  tag標誌位爲9,  字段的符號引用
  • CONSTANT_Methodref_info  tag標誌位爲10,類中方法的符號引用
  • CONSTANT_InterfaceMethodref_info tag標誌位爲11, 接口中方法的符號引用
  • CONSTANT_NameAndType_info tag 標誌位爲12,字段和方法的名稱以及類型的符號引用

5. 類或接口訪問標誌

表示類或者接口方面的訪問信息,比如Class表示的是類還是接口,是否爲public、static、final等。,下面我們就來看看TestClass的訪問標示。Class的訪問標誌值爲0x0021:

根據前面說的各種訪問標示的標誌位,我們可以知道:0x0021=0x0001|0x0020 也即ACC_PUBLIC 和 ACC_SUPER爲真,其中ACC_PUBLIC大家好理解,ACC_SUPER是jdk1.2之後編譯的類都會帶有的標誌。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章