用带参构造器锁死对象初始状态,核心是将关键字段声明为final并在构造器中一次性赋值且校验合法性,如检查null、范围及逻辑约束,确保对象创建即有效不可变。

用带参构造器锁死对象初始状态,核心是把关键字段设为 final,并在构造器中一次性赋值,之后无法修改。
声明 final 字段,禁止后续修改
把不希望被改变的属性声明为 final,Java 会强制要求它们在对象构造完成前(即构造器结束前)必须被初始化,且之后不可再赋值。
public class User {
private final String name;
private final int age;
public User(String name, int age) {
this.name = name;
this.age = age; // ✅ 构造器内赋值,合法
}
}
一旦构造完成,user.name = "xxx" 这类赋值会编译报错。
构造器里做校验,确保状态合法
仅靠 final 不够——它只防改值,不防非法值。应在构造器中加入参数检查,抛出异常阻止无效对象诞生:
- 检查 null:如
if (name == null) throw new IllegalArgumentException("name cannot be null"); - 检查范围:如
if (age 150) throw new IllegalArgumentException("age out of range"); - 检查逻辑约束:如两个参数需满足某种关系(start
避免 this 逸出,防止构造中途被外部访问
如果在构造器中把 this(或其引用)传给其他方法、线程或静态集合,可能在对象尚未构造完成时就被读取或修改,破坏“锁死”效果:
- ❌ 不要在构造器中调用可被子类重写的方法(可能访问未初始化字段)
- ❌ 不要将
this发布到外部作用域(如注册监听器、放入全局 Map) - ✅ 如需发布,先用私有构造器 + 静态工厂方法封装,确保对象完全构造后再暴露
配合不可变设计,真正锁死整个状态
仅 final 字段还不够——若字段本身是可变对象(如 ArrayList),仍可能通过引用修改内容。应进一步:
- 对集合类字段,用
Collections.unmodifiableList(...)封装 - 对自定义对象字段,确保其自身也是不可变的(所有字段 final + 无 setter + 深拷贝返回副本)
- 必要时在 getter 中返回防御性拷贝(如
return new ArrayList(this.items);)

















