类加载的时机
类的完整生命周期分为如下步骤:
flowchart LR
load(加载)-->verification(验证)-->preperation(准备)-->resolution(解析)-->initialization(初始化)-->using(使用)-->unloading(卸载)
classDef circle1 fill:#3e93ef, stroke:#3e93ef, color: #fff;
classDef circle2 fill:#ff8a00, stroke:#ff8a00, color: #fff;
load:::circle1
verification:::circle1
preperation:::circle1
initialization:::circle1
unloading:::circle1
resolution:::circle2
using:::circle2
其中加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,而Java为了支持“动态绑定”,解析有可能在初始化之后。
至于什么时候加载,《Java虚拟机规范》中没有强制约束,但严格规定了有且只有六种情况必须立即对类进行“初始化”(而加载、验证、准备自然需要在此之前开始):
- 初始化对象和使用静态方法或静态属性
- 反射调用类的时候
- 子类被初始化的时候,父类需要先初始化(父子接口之间没有限制)
- 执行主类(包含
main()
方法的那个类) - 如果一个
java.lang.invoke.MethodHandle
实例最后的解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种类型的方法句柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化 - 如果接口中含有默认方法,在起实现类初始化前,要先初始化该接口