侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

简述Java类加载的基本过程

2025-12-13 / 0 评论 / 4 阅读

题目

简述Java类加载的基本过程

信息

  • 类型:问答
  • 难度:⭐

考点

类加载过程,类加载器,双亲委派模型

快速回答

Java类加载分为三个主要阶段:

  1. 加载:查找并加载类的二进制字节码
  2. 链接:包含验证、准备、解析三个子阶段
  3. 初始化:执行类构造器<clinit>()方法

类加载器采用双亲委派模型,优先委派父加载器处理。

解析

一、类加载基本过程

当JVM首次使用类时,会触发以下完整流程:

  1. 加载(Loading)
    • 通过全限定名获取类的二进制字节流
    • 将字节流转化为方法区的运行时数据结构
    • 在堆中生成代表该类的Class对象
  2. 链接(Linking)
    • 验证(Verify):检查字节码安全性(文件格式、元数据等)
    • 准备(Prepare):为静态变量分配内存并设置默认值(如int=0)
    • 解析(Resolve):将符号引用转换为直接引用
  3. 初始化(Initialization)
    • 执行类构造器<clinit>()方法
    • 为静态变量赋程序设定的初始值
    • 执行静态代码块

二、代码示例

public class LoadDemo {
    static int value = 10; // 准备阶段value=0,初始化阶段变为10
    static { System.out.println("静态代码块执行"); }

    public static void main(String[] args) {
        System.out.println(LoadDemo.value);
    }
}

输出顺序:
1. 加载LoadDemo类 → 2. 链接阶段(value初始化为0) → 3. 初始化阶段(value赋值为10,打印"静态代码块执行") → 4. main方法打印10

三、双亲委派模型

类加载器层级结构:

  • Bootstrap ClassLoader:加载JRE/lib核心库(C++实现)
  • Extension ClassLoader:加载JRE/lib/ext扩展库
  • Application ClassLoader:加载classpath用户类

工作流程:
1. 收到加载请求后,先委托父加载器处理
2. 父加载器无法完成时(在自己的搜索范围找不到类),子加载器才尝试加载

四、最佳实践

  • 避免自定义类加载器破坏双亲委派(特殊场景如热部署除外)
  • 静态变量初始化避免循环依赖:
    // 错误示例
    class A { static int val = B.val + 1; }
    class B { static int val = A.val + 1; } // 导致初始化死锁

五、常见错误

  • ClassNotFoundException:类加载器在指定路径找不到类
  • NoClassDefFoundError:编译时存在类,但运行时链接失败
  • 混淆「准备」和「初始化」阶段:误认为准备阶段就会执行静态赋值

六、扩展知识

  • 触发初始化时机:new实例、访问静态变量/方法、反射调用、初始化子类等
  • 不会触发初始化:通过子类引用父类静态字段、数组定义(如MyClass[] arr = new MyClass[10]