标准答案
- 类通常不可继承或保证子类不能破坏不变式,字段设为 private final。
- 构造函数一次性建立合法状态,不暴露 setter 或可修改内部对象的引用。
- 对 Date、集合和数组等可变成员做防御性复制,读取时返回不可变视图或副本。
- 不可变不等于线程安全的所有问题都消失,外部资源和懒加载仍需同步。
题目解析
真正不可变要求对象构造完成后状态不会被外部修改,字段通常 private final,构造时完成校验,类不能被可变子类破坏。final 只保证引用不能重新赋值,不保证引用指向的集合或数组不可变。
对集合、数组和日期类等可变成员要防御性复制,读取时返回副本或不可变视图。复制会带来成本,但换来跨线程共享、缓存和审计上的稳定语义。
懒加载、缓存、外部资源和异步补全会重新引入可变状态,需要单独同步或把它们移出值对象。不可变对象也不自动保证外部资源操作线程安全。
常见误区
- 误区:只把字段声明为 final 就认为对象不可变。改正:检查字段引用的对象、继承、构造校验和公开方法。
- 误区:直接返回内部 List。改正:返回不可变副本或只读视图,并防止构造参数后续修改。
- 误区:构造完成后异步补充关键字段。改正:把关键状态一次性构造,异步数据用独立状态对象或明确生命周期管理。