Java静态代码块由JVM在类初始化阶段自动执行,ClassLoader仅负责加载字节码;调用loadClass()不触发初始化,静态块不执行;需通过访问非编译期常量静态字段、调用静态方法等方式主动触发。

Java静态代码块的执行,本质不是由ClassLoader“主动触发”,而是由JVM在类初始化阶段(Initialization)自动执行——ClassLoader只负责把字节码加载进内存,真正决定“什么时候跑静态块”的,是JVM对类是否需要初始化的判定逻辑。
静态代码块不随ClassLoader.loadClass()执行
调用ClassLoader.loadClass("X")仅完成类的加载(Loading)和链接(Linking),跳过初始化阶段,因此静态代码块**完全不会执行**。这是区分“加载”与“初始化”的关键分水岭。
- 常见误用:以为只要类被加载了,静态块就该跑——实际它还在“待命”状态
- 正确触发方式:访问类的静态字段(非编译期常量)、调用静态方法、new实例、反射调用
Class.forName("X")(默认initialize=true) - 特别注意:
static final int PORT = 8080;这类编译期常量,连初始化都绕过,自然也不会执行静态块
不同ClassLoader加载同一类,静态块各跑一次
若两个隔离的ClassLoader(如Tomcat中WebAppClassLoader和SharedClassLoader)各自加载同一个类名的.class文件,JVM会视为**两个完全不同的类**,各自独立完成初始化——静态代码块也就分别执行一次。
- 结果:两个类的静态变量互不影响,缓存、单例、配置等可能重复初始化
- 典型场景:Web应用热部署、OSGi模块、自定义插件体系
- 验证方式:打印
MyClass.class.getClassLoader(),对比哈希值
父类先于子类初始化,顺序由JVM严格保障
当首次主动使用子类时,JVM会先检查父类是否已初始化;若未初始化,则**强制先完成父类的初始化**(包括其所有静态变量赋值和静态代码块),再执行子类的静态部分。
立即学习“Java免费学习笔记(深入)”;
- 执行顺序固定:父类静态变量 → 父类静态块 → 子类静态变量 → 子类静态块
- 源码中声明位置决定同级执行次序:
static int a = 1;和static { b = 2; }谁写在前面,谁先运行 - 陷阱:子类静态块里调用父类静态方法,该方法若依赖尚未初始化的父类静态字段,会得到默认值(如
null或0)
异常导致类初始化失败,后续使用直接抛错
静态代码块中若抛出未捕获异常(如IOException),JVM会封装为ExceptionInInitializerError,并将该类标记为“初始化失败”。此后任何对该类的主动使用,都会立即抛出同一个错误,不再重试。
- 无法通过try-catch在外部“修复”:类状态已损坏,只能重启JVM或重新加载类(需更换ClassLoader)
- 常见诱因:配置文件缺失、网络资源不可达、静态工具类未就绪却提前调用
- 建议:静态块内尽量只做轻量、确定性高的操作;复杂初始化可延迟到首次方法调用时(如静态holder模式)


















