当前位置: 首页 > news >正文

JVM 类加载过程

一、加载(Loading)

目标:把字节码文件(.class)“读入 JVM”,生成类的 “半成品”(Class 对象)。

  • Bootstrap ClassLoader(启动类加载器)
    • 负责加载 JVM 核心类库(如 java.lang 包),用 C++ 实现(不同 JVM 有差异),无对应的 Java 类。
  • Platform ClassLoader(平台类加载器)
    • 加载 Java 标准库扩展(如 java.sqljavax 包),JDK 9 后从 Extension ClassLoader 改名而来。
  • App ClassLoader(应用类加载器):  
    • 加载项目自己写的类、第三方库(classpath 路径下的类),是开发中最常用的加载器。

类加载器(不同 JDK 版本的差异)

  • 低版本 JDK
    • 启动类加载器:负责加载rt.jar(包含 Java 核心类库)中的类。
    • 扩展类加载器:负责加载ext目录下的扩展类库中的类。
    • 系统类加载器(System ClassLoader):负责加载classpath中程序员自己编写的类。
  • 高版本 JDK(9+,引入模块化思想)
    • 启动类加载器:仍负责加载 JDK 核心类库。
    • 平台类加载器:替代低版本的扩展类加载器,负责加载 Java 平台扩展的非核心类。
    • 应用类加载器:替代低版本的系统类加载器,负责加载classpath中的类。
    • 变化:rt.jarext目录消失,类库被拆分为多个模块(.jmod文件),不同模块由不同类加载器加载。

流程:类加载器按 双亲委派机制 工作(优先让父加载器尝试加载,保证核心类不被篡改),最终找到字节码文件,读入内存并生成 Class 对象,存入方法区。

二、链接(Linking)

目标:把 “半成品类” 变成可执行的 “成品”,拆成 验证、准备、解析 三步:

1. 验证(Verify)
  • 检查字节码是否符合 JVM 规范(比如魔数是否是 0xCAFEBABE、语法是否合法),防止恶意 / 错误字节码搞崩 JVM。
2. 准备(Prepare)
  • 给类的静态变量分配内存 + 设置默认值(比如 static int num = 10,准备阶段会先设 num = 0,真正赋值在初始化阶段)。
  • 注意:静态常量(static final)直接赋 “用户写的值”(比如 static final int num = 10,准备阶段就会设 num = 10 )。
3. 解析(Resolve)
  • 把符号引用替换成直接引用:比如代码里写 Object obj = new Object(),编译后是 “符号引用”(类似 “找名为 Object 的类”),解析阶段会换成内存地址(直接引用),让 JVM 真正能找到对应的类。

三、初始化(Initialization)

目标:执行类的静态代码块、给静态变量赋 “用户写的值”(比如 static int num = 10 在这里真正赋值为 10 )。

  • 触发时机:首次用类的静态成员、创建对象、反射调用等(遵循 主动使用规则 )。
  • 流程:按代码顺序执行静态变量赋值、静态代码块,完成后类才算真正 “可用”。

关键总结

  1. 类加载器:用 “双亲委派” 保证类加载安全,避免核心类被篡改。
  2. 链接阶段:验证字节码合法性 → 给静态变量分配内存 → 把符号引用转成内存地址。
  3. 初始化:执行静态逻辑,给静态变量赋最终值,让类真正 “激活”。

类加载器获取

(1)方式 1:通过当前类的 getClassLoader() 获取

ClassLoader appClassLoader = ReflectTest.class.getClassLoader();

  • 逻辑
    • ReflectTest.class 拿到当前类的 Class 对象,调用 getClassLoader(),获取 “加载当前类的类加载器”。
    • 因 ReflectTest是项目 classpath 内的自定义类,加载它的就是 应用类加载器
  • 作用:验证 “自定义类由应用类加载器加载”。

(2)方式 2:通过 ClassLoader.getSystemClassLoader() 获取

ClassLoader appClassLoader2 = ClassLoader.getSystemClassLoader();

  • 逻辑
    • ClassLoader 是类加载器基,静态方法 getSystemClassLoader() 直接返回 应用类加载器
    • 这是 Java 提供的 “直接获取应用类加载器” 的标准写法。
  • 作用:更直接获取应用类加载器,与方式 1 对比,结果一致。

(3)方式 3:通过线程上下文类加载器获取

ClassLoader appClassLoader3 = Thread.currentThread().getContextClassLoader();
System.out.println("应用类加载器:" + appClassLoader3);

  • 逻辑
    • 每个 Java 线程默认有 “上下文类加载器(Context ClassLoader)”,默认就是 应用类加载器
    • 通过 Thread.currentThread() 拿到当前线程,调用 getContextClassLoader() 获取。
  • 作用:框架(如 Tomcat )中常用,可动态修改上下文类加载器,实现复杂加载逻辑(此处演示默认情况 )。
http://www.lryc.cn/news/586108.html

相关文章:

  • 安全初级作业1
  • Docker-镜像构建原因
  • 十三、K8s自定义资源Operator
  • Java面试基础:面向对象(1)
  • 快速建立UI网站
  • 面试150 翻转二叉树
  • Linux:信号
  • 免费用Claude code薅羊毛
  • c++11——移动语义的举例说明
  • 三维渲染中的抗锯齿技术
  • TinyBERT:知识蒸馏驱动的BERT压缩革命 | 模型小7倍、推理快9倍的轻量化引擎
  • 9.4 自定义SMC服务开发
  • STM32第二十一天定时器TIM
  • Windows环境下解决Matplotlib中文字体显示问题的详细指南
  • 人工智能之数学基础:多元逻辑回归算法的矩阵参数求导
  • Spring(四) 关于AOP的源码解析与思考
  • 【Flask】基础入门
  • Flutter、React Native、Uni-App 的比较与分析
  • 如何防范金融系统中的SQL注入攻击
  • 【LeetCode 热题 100】98. 验证二叉搜索树——(解法一)前序遍历
  • 初等行变换会改变矩阵的什么?不变改变矩阵的什么?求什么时需要初等行变换?求什么时不能初等行变换?
  • 【Go + Gin 实现「双 Token」管理员登录】
  • Linux/Ubuntu安装go
  • 客户资源被挖?营销方案泄露?企业经营信息保护避坑指南
  • Day 3·知识卡片|Python基础:print 函数还能这么玩?
  • 阿里开源AI大模型ThinkSound如何为视频配上灵魂之声
  • Windows X64环境下mysql5.6.51安装指南
  • SpringBootloggers未授权访问漏洞处理
  • 基于MCP的CI/CD流水线:自动化部署到云平台的实践
  • Unity VR手术模拟系统架构分析与数据流设计