JVM类加载续

时间:2023-01-07 06:01:41

上一篇理解了JVM类加载过程的第一个阶段,这篇来说说剩下的阶段:验证、准备、解析、初始化。需要注意的是,这些阶段(解析除外)只是按照这个顺序开始,但是执行的过程中可能存在交叉。

验证:就是要对加载的二进制流文件进行各种检查,很好理解。

准备:为类变量(static)分配内存并设置初始值,即所谓的"零值",但是不包括常量(final)。

解析:将常量池的符号引用替换成直接引用,这个阶段发生时间没有明确规定,但是有具体限制:在符号引用被使用之前,必须被解析。

上述3个阶段合称连接阶段。

初始化:这里是类型初始化,不是对象初始化。

对于第一个阶段--加载,没有明确规定时机,但是初始化阶段有且仅有明确的的4种情况:

1、访问类型的静态成员(final常量除外)和使用new关键字

2、反射调用

3、一个类型的父类型先初始化

4、包含main方法的主类

初始化的过程:编译器自动按顺序收集类变量赋值语句和静态语句块(static{})生成<clinit>()方法,如果一个类型没有类变量赋值以及静态语句块,就不会自动生成。JVM需要保证调用子类的<clinit>()方法前先调用父类的<clinit>()方法(接口不必),同时保证线程安全。

最后,说一个特例,数组类。数组类由JVM自动生成,自动创建。假设自定义类com.fbi.A,A[] arrs = new A[10];语句,JVM会生成"[Lcom.fbi.A"这样的一个类型。这不是重点,真正的重点是这条语句只会去加载类A,但不会初始化类A。