java类装载流程
学习java有一段时间了,很好奇java的虚拟机是怎么加载class的,正好今天有空,就查阅了一些资料,总结了一下,顺便记录下来,有不对之处请网上大神斧正。
一、流程图
- 类加载流程图
1 | graph LR |
- 链接过程又分为三步
1 | graph LR |
二、加载
此阶段是类装载类的第一个阶段,负责通过各种方式获取类的二进制流,转为方法区数据结构,并在JAVA堆中生成对应的java.lang.Class对象
三、链接
3.1 验证
验证的目的是保证Class流的格式是正确的。一个类通过了字节码的验证并不代表该类没有问题,反之如果没有通过字节码的验证,那么该类一定存在问题。
文件格式验证
是否以0xCAFEBABE开头,版本号是否合理
元数据验证
是否有父类,是否继承了final类,非抽象类是否实现了所有的抽象方法(编译环节就通不过,不知道为什么类加载过程中还要验证)。
字节码验证
该验证最复杂,主要运行检查,栈数据类型和操作码数据参数是否吻合,跳转指令指定到合理的位置
- 符号引用验证
常量池中描述类是否存在,访问的方法或字段是否存在且有足够的权限(NoSuchMethodError, NoSuchFieldError,IllegalAccessError错误就发生在该阶段)
3.2 准备
准备阶段主要是分配内存,并在方法区中为类设置初始值。
例如:1
2
3
4public static int a=1;
public static final int b=1;
//1、a=1会在准备阶段先设置为0,在初始化的<clinit>中才会被设置为1
//2、b=1(static final)会在准备阶段直接设置为1,直接赋准确的值。3.3 解析
本阶段是将符号引用替换为直接引用。字符串引用对象不一定被加载,指针或者地址偏移量引用对象一定在内存
四、初始化
- 执行类构造器
:执行static变量赋值语句,static{}语句 - 子类的
调用前保证父类的 被调用 是线程安全的
类的初始化顺序图:1
2
3
4
5
6
7父类静态成员变量-->父类静态初始化块
父类静态初始化块-->子类静态成员变量
子类静态成员变量-->子类静态初始化块
子类静态初始化块-->父类普通成员变量
父类普通成员变量-->父类构造方法
父类构造方法-->子类普通成员变量
子类普通成员变量-->子类构造方法

