Java 类生命周期详解

Java 类的生命周期是指从 加载(Loading) 到 卸载(Unloading) 的整个过程,共分为 7 个阶段。JVM 通过 类加载器(ClassLoader) 和 运行时数据区(Runtime Data Areas) 管理类的生命周期。


1. 类生命周期的 7 个阶段

                                                        

(1) 加载(Loading)

  • 任务:查找并加载类的二进制字节码(.class 文件)。

  • 触发条件

    • new 实例化对象。

    • 访问类的静态字段或方法(static)。

    • 反射调用(Class.forName())。

  • 加载来源

    • 本地文件系统(ClassPath)。

    • JAR 包、网络、动态代理生成等。

  • 关键点

    • 由 类加载器(ClassLoader) 完成。

    • 生成 Class 对象(存储在 方法区)。

(2) 验证(Verification)

  • 任务:确保 .class 文件符合 JVM 规范,防止恶意代码。

  • 检查内容

    • 文件格式(魔数 0xCAFEBABE)。

    • 元数据(如是否继承 final 类)。

    • 字节码合法性(无非法跳转)。

    • 符号引用验证(如能否找到引用的类)。

(3) 准备(Preparation)

  • 任务:为 静态变量 分配内存并设置初始值(零值)。

  • 示例

    static int a = 10;  // 准备阶段 a = 0(初始化阶段才赋值为 10)
    static final int b = 20; // final 修饰的常量直接赋值为 20

(4) 解析(Resolution)

  • 任务:将符号引用(常量池中的 CONSTANT_ClassCONSTANT_Methodref 等)转换为直接引用(内存地址)。

  • 解析目标

    • 类/接口、字段、方法、方法类型等。

(5) 初始化(Initialization)

  • 任务:执行类构造器 <clinit>(),初始化静态变量和静态代码块。

  • 触发条件(首次主动使用时):

    • newgetstaticputstaticinvokestatic 指令。

    • 反射调用。

    • 子类初始化时,父类需先初始化。

  • 线程安全:JVM 保证 <clinit>() 只执行一次(加锁)。

(6) 使用(Using)

  • 任务:类完全加载后,可被程序正常使用(创建对象、调用方法等)。

  • 运行时数据区

    • :存储对象实例。

    • 方法区:存储类信息、静态变量等。

(7) 卸载(Unloading)

  • 任务:从 JVM 中移除类的 Class 对象和字节码。

  • 触发条件

    • 类的所有实例已被 GC。

    • 加载该类的 ClassLoader 已被 GC。

    • 该类对应的 Class 对象无其他地方引用。

  • 应用场景

    • 动态加载(如 OSGi、热部署)。


2. 类加载器(ClassLoader)

(1) 双亲委派模型

                                                       

  • BootstrapClassLoader:加载 JAVA_HOME/lib 下的核心类(如 java.lang.*)。

  • ExtClassLoader:加载 JAVA_HOME/lib/ext 下的扩展类。

  • AppClassLoader:加载 ClassPath 下的用户类。

  • 自定义 ClassLoader:可重写 findClass() 实现特殊加载逻辑。

(2) 打破双亲委派

  • 场景

    • SPI 机制(如 JDBC 驱动加载)。

    • 热部署(如 Tomcat 的 WebAppClassLoader)。

  • 方法:重写 loadClass() 逻辑。


3. 常见面试问题

3.1: 类初始化顺序?

父类静态变量 → 父类静态块 → 子类静态变量 → 子类静态块 →
父类实例变量 → 父类构造块 → 父类构造函数 →
子类实例变量 → 子类构造块 → 子类构造函数

3.2: 什么时候会触发类初始化?

  • 访问 static 字段或方法(除 final 常量)。

  • 反射调用 Class.forName()

  • 子类初始化时父类未初始化。

3.3: <clinit>() 和 <init>() 的区别?

<clinit>()<init>()
类构造器(静态初始化)实例构造器(对象初始化)
由 JVM 调用,线程安全由 new 触发
只执行一次每次 new 都会执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值