类的文件结构
root@Tencent-Debian:~# cat HelloWorld.java
public class HelloWorld {
public static void main(String[] args){
System.out.println("Hello World!");
}
}
root@Tencent-Debian:~# od -t xC HelloWorld.class
0000000 ca fe ba be 00 00 00 37 00 1f 0a 00 06 00 11 09
0000020 00 12 00 13 08 00 14 0a 00 15 00 16 07 00 17 07
0000040 00 18 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
0000060 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e
0000100 75 6d 62 65 72 54 61 62 6c 65 01 00 04 6d 61 69
0000120 6e 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67
0000140 2f 53 74 72 69 6e 67 3b 29 56 01 00 10 4d 65 74
0000160 68 6f 64 50 61 72 61 6d 65 74 65 72 73 01 00 04
0000200 61 72 67 73 01 00 0a 53 6f 75 72 63 65 46 69 6c
0000220 65 01 00 0f 48 65 6c 6c 6f 57 6f 72 6c 64 2e 6a
0000240 61 76 61 0c 00 07 00 08 07 00 19 0c 00 1a 00 1b
0000260 01 00 0c 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 07
0000300 00 1c 0c 00 1d 00 1e 01 00 0a 48 65 6c 6c 6f 57
0000320 6f 72 6c 64 01 00 10 6a 61 76 61 2f 6c 61 6e 67
0000340 2f 4f 62 6a 65 63 74 01 00 10 6a 61 76 61 2f 6c
0000360 61 6e 67 2f 53 79 73 74 65 6d 01 00 03 6f 75 74
0000400 01 00 15 4c 6a 61 76 61 2f 69 6f 2f 50 72 69 6e
0000420 74 53 74 72 65 61 6d 3b 01 00 13 6a 61 76 61 2f
0000440 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d 01 00
0000460 07 70 72 69 6e 74 6c 6e 01 00 15 28 4c 6a 61 76
0000500 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56
0000520 00 21 00 05 00 06 00 00 00 00 00 02 00 01 00 07
0000540 00 08 00 01 00 09 00 00 00 1d 00 01 00 01 00 00
0000560 00 05 2a b7 00 01 b1 00 00 00 01 00 0a 00 00 00
0000600 06 00 01 00 00 00 01 00 09 00 0b 00 0c 00 02 00
0000620 09 00 00 00 25 00 02 00 01 00 00 00 09 b2 00 02
0000640 12 03 b6 00 04 b1 00 00 00 01 00 0a 00 00 00 0a
0000660 00 02 00 00 00 03 00 08 00 04 00 0d 00 00 00 05
0000700 01 00 0e 00 00 00 01 00 0f 00 00 00 02 00 10
0000717
根据JVM规范,类文件结构如下:
1.1魔数
0-3字节,表示它是否是.class类型的文件
ca fe ba be
1.2版本
4-7字节,表示类的版本,如 00 34
(52) 表示是Java 8
1.3常量池
字节码指令
...这一块太多,偏于底层,就不细研究了,直接跳到类加载
类加载
1. 加载
将类的字节码载入方法区中,内部采用C++的instanceKlass描述java类, 它的重要field有:
_java_mirror
即java的类镜像,例如对String
来说,就是String.class
,作用是把klass
暴露给java
使用_super
即父类_fields
即成员变量_methods
即方法_constants
即常量池_class_loader
即类加载器_vtable
虚方法表_itable
接口方法表
- 如果这个类还有父类没有加载,先加载父类
- 加载和链接可能是交替运行的
2. 链接
2.1 验证
验证类是否符合JVM规范,安全性检查
2.2 准备
为static变量分配空间,设置默认值
- 静态变量存储在堆中
- 分配空间和赋值是两个阶段,分配空间是在准备阶段,而赋值是在初始化阶段
- 如果static变量是final的基本类型,以及字符串常量,那么编译阶段值就确定了,赋值在准备阶段完成
- 如果static变量是final 的,但属于引用类型,那么赋值也会在初始化阶段完成
2.3 解析
将常量池中的符号引用解析为直接引用
2.4 初始化
初始化即调用
3.类加载器
名称 | 加载的类 | 说明 |
---|---|---|
Bootstrap ClassLoader | JAVA_HOME/jre/lib | 无法直接访问 |
Extension ClassLoader | JAVA_HOME/jre/lib/ext | 上级为Bootstrap,显示为null |
Application ClassLoader | classpath | 上级为Extension |
自定义类加载器 | 自定义 | 上级为Application |
评论