遇到过这两种离谱问题,你就知道类加载不是“背概念”,而是实打实的工程问题:

  • 线上报错ClassCastException: A cannot be cast to A
  • 本地启动NoSuchMethodError / NoClassDefFoundError,明明依赖里有

这类问题的根子,往往都在 ClassLoader 隔离双亲委派


1. 类加载到底加载了什么

JVM 运行时需要两类东西:

  • 字节码.class 的内容
  • 类元数据:这个类有哪些字段/方法/父类/接口、常量池等

“类加载”不是简单读文件,它的产物是 JVM 里的一个 Class 对象,并且有一个非常关键的身份判定:

  • 类的唯一性 = 类全限定名 + 加载它的 ClassLoader

所以:

  • 同一个 com.xxx.User,被两个不同的 ClassLoader 加载出来,就是 两个互不兼容的类型

2. 类加载全过程:加载 -> 验证 -> 准备 -> 解析 -> 初始化

你常用的理解顺序:

  • 加载(Loading):找到字节码来源(文件/网络/内存/加密包),读进来
  • 验证(Verification):字节码合法性校验
  • 准备(Preparation):给 static 变量分配内存并设默认值
  • 解析(Resolution):把常量池里的符号引用变成直接引用
  • 初始化(Initialization):执行 <clinit>(静态变量赋值、静态代码块)

排障上最重要的是初始化:

  • 什么时候触发初始化?
    • new
    • 访问静态字段/方法
    • 反射调用
    • 子类初始化前会先初始化父类

3. 常见 ClassLoader 分层(你可以按“谁加载谁”记)

典型分层(不同 JVM 实现略有差异,但思路一致):

  • 启动类加载器:加载核心类库(如 java.lang.*
  • 平台/扩展类加载器:加载平台级库
  • 应用类加载器:加载应用 classpath 下的类(我们大多数业务类在这)
  • 自定义类加载器:框架/容器/插件系统常见(Tomcat、OSGi、SPI、热加载等)

4. 双亲委派:它到底“委派”了什么

双亲委派的核心规则:

  • 一个类加载请求到来时
  • 先交给父加载器尝试加载
  • 父加载器加载不了,子加载器才自己加载

目的:

  • 避免核心类库被篡改(你写一个 java.lang.String 不能覆盖系统的)
  • 减少重复加载(父加载过,子就复用)

注意:

  • “双亲”不是指 Java 的继承关系,而是 ClassLoader 的逻辑父子关系

5. 为什么会出现 A cannot be cast to A

你看到的 A 是同名类,但来自不同的 ClassLoader

  • A@ClassLoader1A@ClassLoader2 是两种类型
  • JVM 认为它们不是一个类

常见触发场景:

  • 容器/插件:Tomcat 的 WebAppClassLoader
  • 依赖冲突:同一 jar 被打进了两份(不同路径/不同版本)
  • 自定义加载器:热部署、脚本引擎

排查思路:

  • 打印 obj.getClass().getClassLoader()
  • 对比两边 ClassLoader 是否一致

6. JDK 自带的一个“低成本确认”:看类是从哪加载的

你可以这样确认某个类来自哪个 jar:

  • User.class.getProtectionDomain().getCodeSource().getLocation()

以及确认加载器:

  • User.class.getClassLoader()

7. 你在面试/实战都绕不开的:SPI 与线程上下文类加载器(TCCL)

很多人知道双亲委派,但会被一个问题卡住:

  • JDK 的核心类(父加载器)怎么“反过来”加载你业务 jar 里的实现?

典型例子:JDBC。

解决思路:

  • 通过 线程上下文类加载器(TCCL)
  • 让框架在需要加载实现类时,用 Thread.currentThread().getContextClassLoader() 去加载

这也是为什么你在容器里看到各种“打破双亲委派”的实现:

  • 不是为了破坏规则,而是为了实现 隔离 + 可插拔

8. 最后总结:你应该怎么把它讲清楚

  • 类唯一性:全限定名 + ClassLoader
  • 双亲委派:先父后子,防篡改、少重复
  • 容器/插件系统:靠不同 ClassLoader 做隔离
  • A cannot be cast to A:大概率就是两个 ClassLoader
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐