构造代码块是在对象内存分配并完成默认值填充后、任何构造方法执行前运行的初始化机制,用于统一预检和默认赋值,对所有构造路径生效且不可传参或抛受检异常。

构造代码块(也叫实例初始化块)是 Java 中一种在每次创建对象时、**早于构造方法执行但晚于默认值赋值**的机制,特别适合做统一预检和默认赋值——它天然规避了构造方法重载带来的重复逻辑,也不依赖用户是否调用某个特定构造器。
构造代码块的核心定位
它不是语法糖,而是 JVM 明确支持的初始化阶段:在对象内存分配并完成默认值填充(如 int → 0、String → null)后,立即执行;且在任何构造方法体代码之前运行。这意味着:
- 所有实例变量此时已存在,可安全读写(即使尚未显式赋值)
- 它对所有构造路径生效,包括无参、有参、甚至反射创建的对象
- 不能接收参数,也不可抛出受检异常(除非用 try-catch 包裹)
统一预检:避免空指针与非法状态
当多个字段存在强约束(比如某 String 不得为 null 或空串、某 int 必须 > 0),把校验逻辑集中到构造代码块,能防止遗漏。例如:
class User {
private String name;
private int age;
private String email;
{
// 统一预检
if (name == null || name.trim().isEmpty()) {
name = "匿名用户";
}
if (age age = 18;
}
if (email == null || !email.contains("@")) {
email = "user@example.com";
}
}
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
注意:这里的 name、age、email 在进入代码块时已是默认值(null / 0),所以判空和范围检查是安全的;校验失败后直接设默认值,后续构造方法无需再处理。
默认赋值:比声明处赋值更灵活
虽然可以在字段声明时直接赋值(如 private String status = "active";),但构造代码块支持复杂逻辑:
- 调用工具方法生成默认值(如 UUID、当前时间戳)
- 根据已有字段推导新字段(如 fullName = firstName + " " + lastName;)
- 执行轻量级资源初始化(如 new ArrayList(),避免构造方法里重复 new)
示例:
private List
{
tags = new ArrayList();
tags.add("default");
if (System.currentTimeMillis() % 2 == 0) {
tags.add("even");
}
}
这种动态默认值无法在字段声明行完成,而放在每个构造方法里又违背 DRY 原则。
与构造方法、字段声明赋值的协作顺序
务必记住三者真实执行顺序(按源码书写位置无关,只看 JVM 初始化流程):
- 堆中分配对象 → 所有实例变量设默认值(0 / false / null)
- 执行构造代码块(含字段声明处的赋值,JVM 视其为“隐式构造代码块”)
- 执行构造方法体
因此,构造代码块中看到的字段值,一定是「默认值」或「声明时赋的初值」,绝不会是构造方法里刚塞进去的值——这点决定了它适合做“兜底”而非“覆盖”。










