生命周期

类从被加载到虚拟机内存中开始,到卸载出内存为止,是它的整个生命周期,其中包括

  • 加载 Loading
  • 链接 Linking (验证 Verification,准备 Preparation,解析 Resolution)
  • 初始化 Initialization
  • 使用 Using
  • 卸载 Unloading 7个阶段

阶段顺序

加载、校验、准备、初始化、卸载 这五个阶段的顺序是确定的,但是【解析】则不一定,在某些情况下可以在初始化之后才开始,这样做是为了支持 java 的运行时绑定特征(也称为后期绑定

何时加载

  • 启动main方法时
  • 创建类的实例
  • 创建子类的实例
  • 访问类的静态方法
  • 反射 Class.forName()
    加载时机知识点

加载

通过类的全限定名获取该类的二进制字节流;
将二进制字节流所代表的静态结构转化为方法区的运行时数据结构;
在内存中创建一个代表该类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

链接

验证

验证阶段确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全,包括

  1. 文件格式验证;验证字节流是否符合 Class 文件格式的规范,并且能被当前版本的虚拟机处理
  • 是否以魔数 "0XCAFEBABE" 开头;
  • 主次版本号是否在当前虚拟机处理范围内;
  • 常量池是否有不被支持的常量类型;
  • 指向常量的索引值是否指向了不存在的常量;
  • CONSTANT_Utf8_info 型的常量是否有不符合UTF8编码的数据
  1. 元数据验证;对字节码描述信息进行语义分析,确保其符合 Java 语法规范
  2. 字节码验证;本阶段是验证过程中最复杂的一个阶段,是对方法体进行语义分析,保证方法在运行时不会出现危害虚拟机的事件
  3. 符号引用验证;本阶段发生在解析阶段,确保解析正常执行

准备

准备阶段是正式为类变量(或称 静态成员变量 )分配内存并设置初始值的阶段。这些变量(不包括实例变量)所使用的内存都在方法区中进行分配。初始值通常情况下是数据类型的零值(0, null),假设一个类变量的定义为:

public static int value = 123;

变量value在准备阶段过后的初始值为0而不是123,因为这时候尚未开始执行任何Java方法。如果类字段的字段属性表中存在ConstantValue属性,那么在准备阶段value就会被初始化为 ConstantValue 属性所指定的值,假设上面类变量 value 的定义变为:

public static final int value = 123;

那么在准备阶段虚拟机会根据ConstantValue的设置将value赋值为123。

解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
符号解析知识点

初始化

类初始化阶段是类加载过程的最后一步,是执行类构造器 <clinit>() 方法的过程。<clinit>() 方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static {} 块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的。静态语句块中只能访问定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块中可以赋值,但不能访问

public class FEntity {
    {
        System.out.println("父类非静态代码块");
    }

    static {
        //跟随类加载而加载,只加载一次
        System.out.println("父类静态代码块");
    }

    public FEntity() {
        System.out.println("父类构造方法");
    }

    public void test() {
        System.out.println("father test");
    }
}

public class CEntity extends FEntity {
    {
        System.out.println("子类非静态代码块");
    }

    static {
        //跟随类加载而加载,只加载一次
        System.out.println("子类静态代码块");
    }

    public CEntity() {
        System.out.println("子类构造");
    }

    public void test() {
        System.out.println("child test");
    }
}

public static void main(String[] args) {
    Fentity c = new Centity();
    c.test();
}

输出结果
父类静态代码块
子类静态代码块
父类非静态代码块
父类构造方法
子类非静态代码块
子类构造
child test

参考资料:
https://blog.csdn.net/weixin_42619061/article/details/114708466
https://blog.csdn.net/chenshm/article/details/118659243
https://blog.csdn.net/xing_jian1/article/details/123644728


老污的猫
30 声望5 粉丝