当Class.forName(..., false, ...)时,JVM不会初始化类,故静态代码块和静态字段赋值均不执行;该调用仅完成加载与链接,跳过初始化阶段,符合JVM规范。

当 Class.forName(String name, boolean initialize, ClassLoader loader) 的 initialize 参数设为 false 时,JVM **不会** 初始化该类,也就**不会执行静态代码块和静态字段的赋值语句**。这是 JVM 规范明确保证的行为,不是“阻止”,而是“跳过初始化阶段”。
静态代码块执行的前提是类初始化
Java 中静态代码块(static { ... })只在类的**初始化阶段**执行,而类初始化仅在以下情况触发(JVM 规范 §5.5):
- 首次主动使用该类的静态字段(读写,但
final编译期常量除外) - 首次主动调用该类的静态方法
- 首次创建该类的实例(
new) - 反射调用(如
Class.forName(..., true, ...)) - 子类初始化且父类未初始化
- JVM 启动时指定的主类
而 Class.forName(name, false, loader) 属于**被动引用**:它只加载并链接类(验证、准备),不触发初始化。此时静态代码块自然不会运行。
验证是否真的没执行:加日志观察
可在目标类中加入明显日志,对比不同调用方式:
立即学习“Java免费学习笔记(深入)”;
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
public class TestClass {
static {
System.out.println("静态代码块执行了!");
}
}测试代码:
// 不会打印
Class.forName("TestClass", false, Thread.currentThread().getContextClassLoader());
<p>// 会打印
Class.forName("TestClass", true, Thread.currentThread().getContextClassLoader());注意:类加载 ≠ 类初始化
即使 initialize = false,类仍会被**加载**(查找字节码、解析成 Class 对象)和**链接**(验证、准备——给静态字段赋默认值,如 int → 0,Object → null),但跳过**初始化**(即不执行 <clinit></clinit> 方法,也就是所有 static{} 和 static final 非编译期常量的赋值)。
常见误解与边界情况
以下情况仍可能“看似”触发静态块,但其实与 forName(..., false) 无关:
-
父类已初始化:若父类已被初始化过,子类调用
forName(..., false)不会再触发父类静态块,但也不会触发子类的 -
重复调用
forName(..., true):第二次调用不会再次执行静态块(类已初始化) -
其他主动引用:比如后续代码访问了该类的静态字段,就会触发初始化——这和
forName无关,是 JVM 的按需初始化机制
真正想“完全避免静态块执行”,关键不是改 forName 参数,而是确保在整个生命周期中,该类从未被主动使用。

















