ClassLoader.loadClass() 不触发类初始化,因其仅完成加载和链接(验证、准备),不执行初始化(如静态代码块);这是双亲委派默认行为,符合JVM“首次主动使用才初始化”规范。

ClassLoader.loadClass() 为什么不会触发类初始化
调用 ClassLoader.loadClass() 只完成“加载 + 链接(验证、准备)”,不执行初始化(即不会运行 <clinit></clinit> 方法)。这是双亲委派模型的默认行为,也是实现按需加载的关键。
常见错误现象:你写了静态代码块或静态字段赋值,但发现没执行——大概率是因为只调用了 loadClass(),没调用 Class.forName(String) 或对类做主动引用(如 new 实例、访问静态字段、反射调用方法等)。
-
Class.forName("com.example.Foo")默认会初始化;加第二个参数false就和loadClass()行为一致 - 自定义 ClassLoader 重写
loadClass()时,若跳过双亲委派(比如直接调用defineClass()),仍需手动控制是否调用resolveClass()来触发链接,否则类可能处于“已加载未链接”状态 - JVM 规范只要求“首次主动使用时初始化”,
loadClass()属于被动使用,不触发该时机
自定义 ClassLoader 绕过双亲委派的典型写法与风险
想让子类加载器优先加载(比如热部署、插件隔离),就得在 loadClass() 中跳过 super.loadClass() 调用,改为先自己 findClass(),失败再委托。但这不是简单删掉父调用就行。
容易踩的坑:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 忘记调用
defineClass()返回的Class对象要显式resolveClass(),否则类无法正常使用(抛NoClassDefFoundError或IllegalAccessError) - 同一个字节码被不同 ClassLoader 加载两次,会产生两个不兼容的
Class对象——哪怕全限定名一样,它们的实例也不能互相转型(instanceof失败,强制转换抛ClassCastException) - 如果加载了
java.*或javax.*下的类(哪怕只是同名),JVM 会直接抛SecurityException,这是硬限制,绕不过
双亲委派被破坏的三种真实场景
双亲委派不是铁律,JDK 自己就破了三次,理解它们能帮你判断“什么时候该破、怎么破得安全”。
-
线程上下文类加载器(TCCL):JDBC 的
DriverManager用Thread.currentThread().getContextClassLoader()加载驱动类,因为核心类库(rt.jar)无法直接访问应用路径下的驱动 JAR - OSGi / Spring Boot DevTools:模块化需要打破委派,实现类的细粒度隔离和重载,每个 bundle 或 plugin 拥有独立 ClassLoader,且可导出/导入特定包
-
Tomcat 的 WebAppClassLoader:优先加载
WEB-INF/classes和WEB-INF/lib,仅对java.*、javax.*等极少数包才向上委派,避免应用覆盖容器核心类
如何验证当前类是由哪个 ClassLoader 加载的
别猜,直接查。最可靠的方式是打印 getClass().getClassLoader(),但要注意 null 值的含义。
实操建议:
-
String.class.getClassLoader()返回null—— 表示由启动类加载器(Bootstrap ClassLoader)加载,它用 C++ 实现,Java 层不可见 -
MyClass.class.getClassLoader()返回AppClassLoader或自定义类加载器实例,可进一步调用.getParent()查链路 - 排查类冲突时,用
ClassLoader.getResource("xxx.properties")看资源从哪加载,比看类更直观(尤其涉及 SPI 配置) - JDK9+ 引入模块系统后,
Class.getModule().getLayer().configuration()可查模块层级,但日常诊断还是优先看 ClassLoader 实例本身
真正麻烦的从来不是模型本身,而是同一个类被多个 ClassLoader 同时加载后,堆里存着几份不互通的元数据——这种问题往往在线上静默发生,直到某个 instanceof 判断突然返回 false 或序列化失败才暴露出来。

















