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

Java类加载过程

​Java类加载机制(Class Loading)

类加载是JVM将.class文件加载到内存,并转换成Class对象的过程。整个过程分为​​加载、连接(验证、准备、解析)、初始化​​三个阶段。


一、三个阶段的具体分工​

​1. 加载阶段(Loading)​

  • ​执行者​​:​​类加载器(ClassLoader)​
  • ​任务​​:
    • 根据类的全限定名(如java.lang.String)查找.class文件的二进制数据(本地文件、网络等)加载到JVM内存。
    • JVM将二进制数据读入内存,并在堆中生成一个Class对象(后续反射的入口)。
  • ​关键点​​:
    • 类加载器通过findClass()defineClass()方法完成加载。
    • 双亲委派模型在此阶段生效(优先委派父加载器加载)。

​2. 连接阶段(Linking)​

  • ​执行者​​:​​JVM(而非类加载器)​
  • ​子阶段​​:
    1. ​验证(Verification)​​:检查字节码是否符合JVM规范(如魔数、语法校验)。
    2. ​准备(Preparation)​​:为静态变量分配内存并赋默认值(如int默认为0)。
    3. ​解析(Resolution)​​:将符号引用(如类名、方法名)转为直接引用(内存地址)。
  • ​关键点​​:
    • 连接阶段由JVM内部实现,类加载器不直接参与。
    • 解析阶段可能触发其他类的加载(如类A引用了类B,需先加载类B)。

​3. 初始化阶段(Initialization)​

  • ​执行者​​:​​JVM(调用类加载器加载的代码)​
  • ​任务​​:
    • 执行静态代码块(static{})和静态变量的显式赋值。
    • 初始化父类(如果尚未初始化)。
  • ​关键点​​:
    • JVM通过执行<clinit>方法(编译器生成的类初始化方法)完成初始化。
    • 类加载器仅负责加载类的字节码,不控制初始化逻辑。

​二、类加载器(ClassLoader)​

​1. 分类​

加载器加载路径备注
​Bootstrap ClassLoader​JRE/lib/rt.jar等核心库C++实现,父加载器为null
​Extension ClassLoader​JRE/lib/ext目录加载扩展类
​Application ClassLoader​用户程序的classpath(如./target/classes默认的类加载器
​自定义ClassLoader​用户指定路径需继承ClassLoader

​2. 双亲委派模型(Parents Delegation)​

  • ​规则​​:类加载请求优先委派给父加载器处理,父加载器无法完成时才自己加载。
  • ​目的​​:避免重复加载,保证核心类(如java.lang.Object)的安全性和唯一性。
// 双亲委派的代码实现(ClassLoader.loadClass())
protected Class<?> loadClass(String name, boolean resolve) {synchronized (getClassLoadingLock(name)) {// 1. 检查是否已加载Class<?> c = findLoadedClass(name);if (c == null) {// 2. 委派给父加载器try {if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {}// 3. 父加载器失败后自行加载if (c == null) {c = findClass(name);}}return c;}
}

​三、破坏双亲委派的场景​

  1. ​SPI(Service Provider Interface)​
    • 如JDBC的DriverManager需加载不同厂商的实现类(通过Thread.currentThread().getContextClassLoader())。
  2. ​热部署​​(如Tomcat)
    • 每个Web应用使用独立的ClassLoader,优先加载自身路径的类。

​四、类加载的面试问题​

​1. 类加载的触发条件?​

  • 主动使用类时(如new、静态方法调用、反射等),但被动引用(如子类调用父类静态变量)不会触发子类初始化。

​2. 静态代码块、构造代码块、构造方法的执行顺序?​

public class Example {static { System.out.println("静态代码块"); } // 类初始化时执行{ System.out.println("构造代码块"); }       // 每次new对象时执行(在构造方法前)public Example() { System.out.println("构造方法"); }
}

​输出​​:

静态代码块
构造代码块
构造方法

​3. 如何自定义ClassLoader?​

  • 继承ClassLoader,重写findClass()方法(通常不破坏双亲委派)。

​五、总结​

  • ​类加载流程​​:加载 → 验证 → 准备 → 解析 → 初始化。
  • ​双亲委派​​:保证核心类安全,但可被SPI、热部署等场景打破。
  • ​应用场景​​:热加载、模块化、代码加密(如自定义ClassLoader解密字节码)。
http://www.xdnf.cn/news/12279.html

相关文章:

  • 使用子树合并策略更新git项目的部分目录
  • ignore文件不生效的问题
  • 初识硬编码(x86指令描述)
  • 代码随想录算法训练营第九天| 151.翻转字符串里的单词、55.右旋转字符串 、字符串总结
  • CLIP多模态大模型的优势及其在边缘计算中的应用
  • 实时云渲染解决UE像素流送无法进行二次开发的问题
  • spring注解之配置注解
  • 《图解技术体系》How Redis Architecture Evolves?
  • 【科研绘图系列】R语言绘制和弦图(Chord diagram plot)
  • 大模型数据流处理实战:Vue+NDJSON的Markdown安全渲染架构
  • 高防服务器能够抵御哪些网络攻击呢?
  • 宠物空气净化器哪个好用?2025宠物空气净化器测评:352、希喂、有哈
  • 智慧园区数字孪生全链交付方案:降本增效30%,多案例实践驱动全周期交付
  • 基于正点原子阿波罗F429开发板的LWIP应用(5)——TFTP在线升级功能
  • Spring之事务管理方式
  • Go中的协程并发和并发panic处理
  • GitHub 趋势日报 (2025年06月04日)
  • Linux --环境变量,虚拟地址空间
  • 强化学习在LLM中应用:RLHF、DPO
  • 网络通信核心概念全解析:从IP地址到TCP/UDP实战
  • 面试题:Java多线程并发
  • JAVA之 Lambda
  • chrome使用手机调试触屏web
  • Nginx学习笔记
  • 【Go语言基础【2】】数据类型之基础数据类型:数字、字符、布尔、枚举、自定义
  • Unity3D中Newtonsoft.Json序列化优化策略
  • [蓝桥杯]倍数问题
  • 倍福 PLC程序解读
  • kubectl 命令
  • docker 搭建php 开发环境 添加扩展redis、swoole、xdebug(2)