JVM详解之类加载
一、类的加载过程(生命周期)
1. 说说类加载分为几步
1-1都谁需要加载?
在Java中数据类型分为基本数据类型和引用数据类型。
基本数据类型由虚拟机预先定义,引用数据类型则需要进行类加载
1-2.类加载的步骤
装载
链接:
验证
准备
解析
初始化
类的使用
类的销毁
2. 类加载流程图
3. Loading(装载)阶段
3-1 装载阶段做了什么
所谓装载,就是将Java类的字节码文件加载到机器内存中,并在内存中构建出Java类的原型----类模板对象
装载阶段,就是查找并加载类的二进制数据,生成Class的实例
3-2 类模板对象
类模板对象,就好比Java类的"设计图纸",JVM将其都存在"方法区"中,有了类模板对象,才能在程序运行时通过反射机制来了解和操作这个了类
JDK1.8 之前,存在方法区 但 JDK1.8 之后,存在元空间
3-3 二进制流的获取方式
3-4 Class实例的存储位置
将.clas文件加载至元空间后,会在堆中创建一个Java.long.Class对象,用来封装类位于方法区内的数据结构
该Class对象是在加载类的过程创建的,每个类都应有一个Class类型的对象。
3-5 数组类的加载
数组类本身并不是由类加载器负责创建的,而是由JVM在运行时根据需要而直接创建的,但数组的元素类型仍需要依靠类加载器去创建。
创建数组类的过程:
如果数组元素类型是引用类型,那就遵循定义的加载过程递归加载和创建数组的元素类型
JVM使用指定的元素类型和数组维度来创建新的数组类
如果数组的元素类型是引用数据类型,数组类的可访问性就由元素类型的可访问性决定。
4. Linking(链接)阶段
4-1 验证
验证是链接操作的第一步,它的目的是保证加载的字节码是合法,合理并符合规范的
4-2 准备
准备阶段就是为类的静态变量分配内存,并将其初始化为默认值。
注意:
不包含基本数据类型的字段用static final 修饰的情况,因为final在编译的时候就会分配了,准备阶段会显式赋值
5. 解析
简而言之,将类,接口,字段和方法的符号引用转为直接引用
5 Initialization(初始化)阶段
5-1 子类加载前先加载父类
在加载类之前,虚拟机会先加载该类的父类。
因此父类的<clinit>总是在子类的<clinit>之前被调用。因此父类的static块优先级高于子类
5-2 那些类不会生成<clinit>方法
5.2.1 类中没有声明任何类变量,也没有静态代码块
5.2.2 类中声明类变量,但没使用类变量的初始化语句以及静态代码块来执行初始化操作
5.2.3 类中包含static final修饰的基本数据类型的字段
/**
* 哪些场景下,java编译器就不会生成<clinit>()方法
*/
public class InitializationTest1 {
//场景1:对于非静态的字段,不管是否进行了显式赋值,都不会生成<clinit>()方法
public int num = 1;
//场景2:静态的字段,没有显式的赋值,不会生成<clinit>()方法
public static int num1;
//场景3:比如对于声明为static final的基本数据类型的字段,不管是否进行了显式赋值,都不会生成<clinit>()方法
public static final int num2 = 1;
}