类加载机制
类的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段
类加载的过程包括了:加载->验证->准备 ->解析-> 初始化
按顺序开始,而不是按顺序进行或完成,通常都是互相交叉地混合进行,在一个阶段执行的过程中调用或激活另一个阶段
加载
通过一个类的全限定名来获取定义的二进制字节流,将这个字节流保存到方法区,在java堆中生成一个代表这个类的java.lang.Class对象,和堆中数据关联起来
加载阶段可控性最强,因为类的加载器可以用系统的,也可以用自己写的加载器(ClassLoader
)验证
确保Class文件中的字节流包含的信息符合当前虚拟机的要求,不会危害虚拟机的自身安全(Class文件不一定是java代码编译过来的)
验证包括四个阶段:
文件格式的验证
(验证字节流是否符合Class文件格式的规范,并且能否被当前版本的虚拟机版本处理),
元数据的验证
(对类的元数据信息进行语义校验,保证所有元数据信息都符合java语法规范),
字节码验证
(进行数据流和控制流分析,对类的方法进行校验分析,以保证被校验的类的方法在运行时不会做出危害虚拟机安全的行为),
符号引用验证
(这是最后一个阶段,主要对类自身以外的信息进行匹配性校验)准备
为类变量(静态变量)分配内存,并设置类变量初始值的阶段
内存分配仅包括类变量(static),不包含实例变量,实例变量会在对象实例话时随着对象一起分配在java堆中
前面设置的初始值通常情况下是数据类型默认的零值(如:0,0L,null,false,ect),而不是被在java代码中被显示地赋予的值
public static int value =100;这时value=0
public static final int value=100;这时value=100(特例)
- 解析
虚拟机将常量池中的符号引用转化为直接引用的过程,虚拟机实现对第一次解析的结果进行缓存(在运行时常量池中记录直接引用,并把常量标示为解析状态),从而避免解析动作重复进行。
解析动作主要针对类或接口、字段、类方法、接口方法四类符号引用进行
- 初始化
类初始化是类加载的最后一个阶段,到初始化阶段,才是真正开始执行类中的java程序代码- 什么时候进行初始化?
1、 当遇到new、getstatic、putstatic、invokestatic这四条字节码指令时,如果类还没有进行过初始化则开始进行初始化
2、使用java.lang.refect包的方法对类进行反射调用时,如果类还没有进行过初始化
3、 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发父类的初始化
4、 当虚拟机启东时,用户需要指定一个要执行的主类,虚拟机先执行该主类。
只要这四种情况才会触发类的初始化,称为对一个类进行主动引用,除此之外的所有引用类的方式都不会触发初始化,诚为被动引用