一个类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期将会经历加载、验证、准备、解析、初始化、使用和卸载七个阶段,其中验证、准备、解析三个部分统称为连接。
系统加载 Class 类型的文件主要三步:加载->连接->初始化。连接过程又可分为三步:验证->准备->解析。
加载是类加载过程的第一个阶段,在加载阶段,虚拟机需要完成以下三件事情
加载.class文件的方式
确保被加载的类的正确性
验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
为类的静态变量分配内存,并将其初始化为默认值
static
),而不包括实例变量,实例变量会在对象实例化时随着对象一块分配在Java堆中。0
、0L
、null
、false
等),而不是被在Java代码中被显式地赋予的值。注意:JDK 7 之前,HotSpot 使用永久代来实现方法区的时候,类变量所使用的内存都应当在 永久的 中进行分配。 而在 JDK 7 及之后,HotSpot 已经把原本放在永久代的字符串常量池、静态变量等移动到堆中,这个时候类变量则会随着 Class 对象一起存放在 Java 堆中。
虚拟机将常量池内的符号引用替换为直接引用的过程
解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符 7 类符号引用进行
当一个JVM在启动之后,其中可能包含的类非常多,是不是每个类都会被初始化呢?答案是否定的。
JVM对类的初始化是一个延迟机制,当一个类在首次使用的时候才会被初始化,在同一个运行时package下,一个Class只会被初始化一次。
《Java虚拟机规范》则是严格规定了有且只有6种情况下必须立即对类进行初始化(而加载、验证、准备自然需要在此之前开始)
通过new关键字会导致类的初始化
访问类的静态变量,包括读取和更新会导致类的初始化
访问类的静态方法,也会导致类初始化
初始化子类会导致父类被初始化
对某个类进行反射操作。会导致类被初始化
启动类,就是执行main函数所在的类会导致该类被初始化
注意:构造某个类的数组时并不会导致该类的初始化
参考内容
《深入理解 Java 虚拟机》