类装载的执行过程
类从加载到虚拟机中开始,直到卸载为止,它的整个生命周期包括了:加载、验证、准备、解析、初始化、使用和卸载这7个阶段。其中,验证、准备和解析这三个部分统称为连接(linking)。
1.加载
通过类的全名,获取类的二进制数据流。
解析类的二进制数据流为方法区内的数据结构(Java类模型)
创建java.lang.Class类的实例,表示该类型。作为方法区这个类的各种数据的 访问入口。
把该类的二进制数据流读入到运行时数据区,在元空间中存储类的信息。在堆中开辟一个空间,存储当前类的Class对象,方便后期创建对象时使用。
2.验证
验证类是否符合JVM规范,安全性检查
(1)文件格式验证:
是否符合Class文件的规范。
(2)元数据验证:
这个类是否有父类(除了Object这个类之外,其余的类都应该有父类)
这个类是否继承(extends)了被final修饰过的类(被final修饰过的类表示类不能被继承)
类中的字段、方法是否与父类产生矛盾。(被final修饰过的方法或字段是不能 覆盖的)
(3)字节码验证:
主要的目的是通过对数据流和控制流的分析,确定程序语义是合法的、符合逻辑的。
(4)符号引用验证:
Class文件在其常量池会通过字符串记录自己将要使用的其他类或者方法,检查它们是否存在例:方法或者类在引用时,都会到常量池中查表翻译,找到对应的类或方法。符号引用验证主要就是判断这些类或方法是否存在,不存在就会报错。
注:1、2、3都是格式检验,如:文件格式是否错误、语法是否错误、字节码是否合规。
3.准备
为类变量分配内存并设置类变量初始值
1.static变量,分配空间在准备阶段完成(设置默认值),赋值在初始化阶段完成。
2.static变量是final的基本类型(因为其值不能再被修改),以及字符串常量,值已确定,赋值在准备阶段完成。
3.static变量是final的引用类型,那么赋值也会在初始化阶段完成。
说明:
1.b在准备阶段只会赋默认值0(int类型的默认值就是0),赋值在初始化阶段(b = 10)。
2.c、d在准备阶段就会赋值完成 c = 20;d = "hello";
3.obj是引用类型,也是在初始化阶段赋值。
4.解析
把类中的符号引用转换为直接引用
比如:方法中调用了其他方法,方法名可以理解为符号引用,而直接引用就是使用指针直接指向方法。
说明:这里一开始是符号引用,#4 --> #25 --> #32 -> 对应方法。而直接引用就是直接找到对应要执行的方法。
5.初始化
对类的静态变量,静态代码块执行初始化操作。
初始化规则:
如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。
如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。
6.使用
JVM 开始从入口方法开始执行用户的程序代码
调用静态类成员信息(比如:静态字段、静态方法)
使用new关键字为其创建对象实例
这两种情况都算类被实际使用
7.卸载
当类不再被使用,且没有任何活跃的类加载器实例时,类及其相关的资源将被垃圾回收器回收。
小结