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之后编译的类都会带有的标志。