1. 全景图:类的生命周期

一个类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期经历 7 个阶段:

加载 (Loading) -> 验证 -> 准备 -> 解析 -> 初始化 (Initialization) -> 使用 -> 卸载

  • 连接 (Linking):中间的 验证准备解析 三步合称为连接。


2. 深度拆解:关键阶段

① 加载 (Loading)
  • 任务

    1. 找到“蓝图”(二进制字节流)。

    2. 在内存(堆)中生成一个代表该类的 java.lang.Class 对象。

  • 来源不限

    • 硬盘文件 (.class)。

    • 压缩包 (jar, war)。

    • 动态代理 (Dynamic Proxy):运行时在内存中现场生成(Spring/MyBatis 的核心)。

    • 网络下载、数据库读取等。

② 准备 (Preparation)  面试高频坑
  • 任务:为类变量(static)分配内存,并设置零值(默认值)

  • 案例对比

    Java
    // 情况 A:普通静态变量
    public static int value = 123;
    // 准备阶段结果:value = 0 (JVM 只分配内存,不赋值)
    // 初始化阶段结果:value = 123 (这步才赋值)
    
    // 情况 B:静态常量 (final)
    public static final int value = 123;
    // 准备阶段结果:value = 123 (final 变量会直接确值)
    
③ 初始化 (Initialization)
  • 本质:执行类构造器 <clinit>() 方法的过程。

    • <clinit> 是编译器自动收集所有 静态变量赋值静态代码块 (static {}) 合并而成的。

  • 执行顺序

    • 父类优先:父类 <clinit> -> 子类 <clinit> -> main 方法。

    • 静态优先:静态块先于构造方法执行。


3. 幕后工头:类加载器 (ClassLoader)

层级结构 (Hierarchy)
  1. 启动类加载器 (Bootstrap)

    • 负责加载 JDK 核心库 (rt.jar, java.lang.*)。

    • C++ 实现,Java 代码获取不到(为 null)。

  2. 扩展类加载器 (Extension/Platform)

    • 负责加载扩展库 (javax.*)。

  3. 应用程序类加载器 (Application)

    • 负责加载用户代码 (Classpath) 和第三方 Jar 包。

双亲委派模型 (Parents Delegation Model)
  • 机制“向上啃老,向下甩锅”

    • 当一个加载器收到请求,它自己先不干,直接扔给父加载器。

    • 只有当父加载器反馈“我加载不了”时,子加载器才尝试自己加载。

  • 核心作用

    1. 沙箱安全:防止核心 API 被篡改。

      • 例子:如果你自己写个 java.lang.String,请求会一直传到 Bootstrap 加载器,它发现核心库里已经有 String 了,直接加载原版的,根本不理你的“冒牌货”。

    2. 避免重复:保证在内存中,同一个类永远只有一份。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐