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之後編譯的類都會帶有的標誌。