详解JVM之Class类文件(从源码到Class类文件)
01 Java虚拟机学习过程
画图表示Java文件从编译到Java虚拟机的大致过程:
image- (1)、java源代码经过javac编译为class类文件
- (2)、class类文件经过类加载器ClassLoader被加载到虚拟机
- (3)、Java虚拟机各种执行过程(垃圾回收、本地调用等等)
02 Java源码到类文件
2.1 前期编译
随意找个.java文件,
javac -g:vars Test.java ---> Test.class
前期编译大致过程 :
Test.java->词法分析器->tokens流->语法分析器->语法树/抽象语法树->
语义分析器->注解抽象语法树->字节码生成器->Test.class文件
2.2 16进制查看
找到class文件,用文本编辑器16进制查看器打开
CA FE BA BE 00 00 00 32 00 9F 0A 00 28 00 5D 07
00 5E 0A 00 02 00 5D 0A 00 02 00 5F 0A 00 60 00
61 0A 00 60 00 62 05 00 00 00 00 00 02 BF 20 05
00 00 00 00 00 00 00 B4 07 00 63 0A 00 0B 00 5D
08 00 64 0A 00 0B 00 65 0A 00 0B 00 66 0A 00 27
00 67 08 00 68 0A 00 69 00 6A 08 00 6B 0A 00 25
00 6C 0A 00 69 00 6D 0A 00 69 00 6E 0A 00 27 00
6F 07 00 70 0A 00 18 00 71 07 00 72 0A 00 1A 00
71 07 00 73 0A 00 1C 00 5D 0A 00 74 00 75 0A 00
25 00 76 08 00 77 0A 00 1C 00 78 0A 00 1C 00 66
0A 00 79 00 7A 0A 00 25 00 7B 07 00 7C 0A 00 25
00 7D 07 00 7E 07 00 7F 01 00 06 3C 69 6E 69 74
3E 01 00 03 28 29 56 01 00 04 43 6F 64 65 01 00
0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65
01 00 12 4C 6F 63 61 6C 56 61 72 69 61 62 6C 65
...
2.3 class文件结构
参考官网,一个class文件由一个单一的ClassFile结构组成:
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];
}
- u4 magic;
magic:The magic item supplies the magic number identifying the class file
format
魔法数字,固定为CAFEBABE,比如刚才的class文件用16进制编辑查看:
CA FE BA BE 00 00 00 32 00 9F 0A 00 28 00 5D 07
00 5E 0A 00 02 00 5D 0A 00 02 00 5F 0A 00 60 00
61 0A 00 60 00 62 05 00 00 00 00 00 02 BF 20 05
00 00 00 00 00 00 00 B4 07 00 63 0A 00 0B 00 5D
- u2 minor_version; 和 u2 major_version;
拿刚才的16进制数据
00 00 00 32
其中u2表示minor version,00 0016进制进行10进制转换,就是0;第2个u2继续取 00 32再次进行10进制转换表示10进制的50,也就是jdk6
Java 类文件主要版本到实际 Java JDK 版本的映射
image- u2 constant_pool_count;
取刚才的数据00 9F转为10进制159
constant_pool_count:
The value of the constant_pool_count item is equal to the number of entries
in the constant_pool table plus one.
表示常量池中的数量是158
cp_info constant_pool[constant_pool_count-1]
The constant_pool is a table of structures representing various string
constants, class and interface names, field names, and other constants that
are referred to within the ClassFile structure and its substructures. The
format of each constant_pool table entry is indicated by its first “tag”
byte.
The constant_pool table is indexed from 1 to constant_pool_count - 1.
注意:常量池主要存储字面量(Literal)和符号引用(Symbolic References)
字面量:文本字符串,final修饰等
符号引用:类和接口的全限定名、字段名称和描述符、方法名称和描述符
2.4 javap验证
javap是JDK自带的命令,使用命令javap -v -p Test.class进行反编译,可以查看字节码信息和指令等信息。
信息太多,可以使用命令将日志保存到文件里
javap -v -p Test.class > javaplog.txt
image
image
2.5 Constant Pool analysis
参考oracle官网对Jvm的比较详细的描述,
constant_pool表条目都具有以下通用格式
cp_info {
u1 tag;
u1 info[];
}
image
ok,描述得比较难理解,所以还是以刚才的例子进行说明:
- (1) 参考官网的CONSTANT_Fieldref_info规范,拿上面例子的16进制数据,继续往下数,u1 tag;,这个表示一个字节,所以就是0A,0A表示10进制10,对照表格表示代表的是CONSTANT_Methodref,表示这是一个方法引用
CA FE BA BE 00 00 00 32 00 9F 0A 00 28 00 5D 07
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
往下数:
u2 class_index;:00 28 ->40(10进制),代表的是class_index,表示该方法所属的类在常量池中的索引
u2 name_and_type_index;:00 5D ->93(10进制),代表的是name_and_type_index,表示该方法的名称和类型的索引
拿刚才的javap信息对对比,确实是这样的,所以按照官网规范就可以进行class文件的学习:
image- (2) 往下分析,CONSTANT_Class_info,CONSTANT_Class_info结构用于表示一个类或一个接口
CA FE BA BE 00 00 00 32 00 9F 0A 00 28 00 5D 07
00 5E 0A 00 02 00 5D 0A 00 02 00 5F 0A 00 60 00
07->7(10进制),对比表格表示CONSTANT_Class
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
u2 name_index;:00 5E->94(10进制),类或接口名称索引
#2 = Class #94 // java/util/Date
ok,按照官网规范,学会怎么看之后,就比较容易理解,javap其它就不详细描述了,按照官网规范对就行
image