构造代码块是类中用{}包裹、位于方法外的无名代码块,每次创建对象时自动执行一次且在所有构造器体之前运行,用于统一初始化实例字段、设默认值或记录日志等通用逻辑。

直接用实例初始化块(即构造代码块)就能做到——它会在每次 new 对象时,自动插入到每个构造器的第一行(super() 或 this() 之后),无需修改任何已有构造器,也不影响重载结构。
什么是构造代码块
就是类中用 { } 包裹、写在方法外面的一段代码。它没有名字、不接收参数,但属于每个实例:每次创建对象都会执行一次,且一定在所有构造器体之前运行。
例如:
- 给集合字段设默认值:{ tags = new ArrayList(); }
- 统一设初始状态:{ status = "ACTIVE"; version = 1; }
- 记录创建行为:{ System.out.println("User created"); instanceCount++; }
为什么它能替代重复赋值
编译器会把每个构造代码块的内容,原样复制并插入到每一个构造器的开头(super() 或 this() 调用之后)。你只写一次 { },所有已有构造器就自动获得这段逻辑。
这意味着:
- 不用改构造器签名,也不用加 new 语句
- 新增或删减构造器时,公共初始化逻辑仍自动生效
- 避免因漏写某处导致字段未初始化、空指针等低级错误
和 this() 委托搭配更清晰
构造代码块不能访问构造器参数,所以参数相关逻辑(如 name、age 赋值)还得留在构造器里。推荐组合使用:
- 用构造代码块处理“无参通用逻辑”:初始化集合、打日志、设标志位、注册监听
- 用 this() 把多个构造器归并到一个主构造器,集中处理参数校验与赋值
这样职责分明,既保留重载外观,又不易遗漏初始化步骤。
要注意的几个边界
构造代码块虽好,但有几条硬约束必须留意:
- 不能访问构造器形参(比如 name、type),否则编译报错
- 可以为非静态 final 字段赋值(如 final String id; → { id = UUID.randomUUID().toString(); }),但后续构造器不能再重复赋值
- 不能引用定义在它之后的实例变量(前向引用错误)
- 多个构造代码块按源码顺序依次执行

















