java代码块执行顺序需通过线程安全列表记录可观察痕迹:静态块→实例块→构造器,继承结构下为s-parent→s-child→i-parent→c-parent→i-child→c-child,且静态部分仅首次触发。

测试 Java 代码块执行顺序,核心是让每个代码块产生**可观察、可断言的时序痕迹**,而不是依赖肉眼读代码或 IDE 高亮。静态块、实例块、构造器、字段初始化等按 JVM 规范严格串行执行,但它们本身不返回值,所以必须借助外部状态记录。
用线程安全列表捕获执行序列
定义一个 static final ListCopyOnWriteArrayList),在各类代码块中添加唯一标识字符串。JVM 类加载和对象创建过程天然单线程,该列表能真实反映执行顺序。
- 静态块里加
log.add("S-Parent") - 实例块里加
log.add("I-Child") - 构造器第一行加
log.add("C-Child()") - 字段初始化方法中也插入日志(如
name = loadName()内打印)
通过继承结构验证完整链路
只测单个类容易漏掉父子关系中的关键约束。写一对父类 Parent 和子类 Child,分别在静态块、实例块、构造器中打点,然后执行 new Child()。预期输出顺序为:
-
S-Parent→S-Child(类加载阶段,仅首次) -
I-Parent→C-Parent()→I-Child→C-Child()(每次 new)
运行两次 new Child(),确认静态部分只出现一次,实例部分重复出现。
用反射区分“加载”与“初始化”
调用 Class.forName("X") 会触发静态初始化;而 ClassLoader.getSystemClassLoader().loadClass("X") 只加载不初始化。对比两者后执行 new X() 的日志差异,能验证静态块是否真由“首次主动使用”触发。
- 前者:先输出静态日志,再输出实例日志
- 后者:第一次
new时才补上静态日志,说明类此前未初始化
避免干扰因素确保结果干净
以下情况会让测试失真,需提前排除:
- 不要在构造器中调用可能被重写的方法(子类实例块尚未执行,字段为 null)
- 不用 Lambda 或多线程——它们会破坏执行流的确定性
- 不依赖
final static基本类型常量(编译期内联,跳过类初始化) - 不把局部代码块(方法内的
{})误当作实例块来测
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











