构造代码块在对象初始化中可做统一前置处理,如开启事务、校验字段、防御性初始化等,它在每次创建对象时执行且早于构造方法,适合实例专属初始化。

构造代码块在对象初始化中能做什么
构造代码块(即非静态代码块)在每次创建对象时都会执行,且早于构造方法。它天然适合做对象级的统一前置处理,比如开启事务上下文、校验必填字段、初始化不可变状态、设置默认安全策略等。它不依赖构造函数签名,也不像静态块那样只执行一次,因此是“每个实例专属初始化”的理想位置。
用构造代码块开启事务上下文
在需要事务保障的业务对象中(如订单处理器、账户操作器),可在构造代码块里主动绑定当前线程的事务资源,避免遗漏或重复开启。
- 使用 ThreadLocal 绑定事务 ID 或 Transaction 对象,确保后续 DAO 层可感知
- 调用事务管理器的 begin() 方法,捕获异常并回滚或抛出运行时异常
- 注意:若事务需跨方法传播,应配合 AOP 或显式传递,构造代码块本身不支持自动传播
示例片段:
{ Transaction tx = TransactionManager.begin(); if (tx == null) { throw new IllegalStateException("无法开启事务"); } this.transaction = tx; // 保存到实例字段供后续使用 }用构造代码块实现变量保护与防御性初始化
构造代码块在字段声明初始化之后、构造方法之前执行,可以对已赋初值的字段做二次校验和加固,防止构造函数绕过保护逻辑。
- 检查关键字段是否为 null 或非法值,立即抛出 IllegalArgumentException
- 对集合类字段(如 List、Map)进行防御性复制或转为不可修改视图
- 将传入的可变对象(如 Date、StringBuilder)封装为不可变副本
示例片段:
{ if (this.userId == null || this.userId.trim().isEmpty()) { throw new IllegalArgumentException("userId 不可为空"); } this.tags = Collections.unmodifiableList(new ArrayList(tags)); this.createdAt = new Date(this.createdAt.getTime()); // 防止外部篡改 }构造代码块 + 构造函数的协作要点
构造代码块不是万能替代,它和构造函数要各司其职:
- 构造代码块负责通用、强制、无参依赖的初始化(如事务、校验、防御包装)
- 构造函数负责差异化、业务语义明确的赋值(如设置订单类型、关联ID、状态机起点)
- 避免在构造代码块中调用可能被子类重写的方法(存在 this 引用逃逸风险)
- 若类有多个构造函数,构造代码块会统一生效,比在每个构造函数里重复写更安全可靠










