要自定义不可变类,需满足:1. 所有字段为private final;2. 不提供修改状态的方法,getter返回副本或不可变包装;3. 构造时对可变组件做防御性拷贝;4. 类声明为final以防止继承破坏不可变性。

要自定义一个不可变类,核心是确保该类的实例一旦创建,其状态就无法被修改。Java 中没有直接的 immutable 关键字,需通过编码规范和语言特性共同保障。
1. 所有字段必须是 private final
这是不可变性的基础。private 防止外部访问,final 保证引用(或基本类型值)在构造后不再改变。
例如:
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = Objects.requireNonNull(name);
this.age = age;
}
// getter 方法(无 setter)
public String getName() { return name; }
public int getAge() { return age; }
}
2. 不提供任何修改状态的方法
禁止定义 setter、addXXX、clear 等会改变内部字段的方法。所有公开方法应只读,或返回新对象(如字符串操作返回新 String)。
常见错误:返回可变对象的引用
- ❌ 错误:返回内部数组或集合的原始引用(调用方可直接修改)
- ✅ 正确:返回副本(
Arrays.copyOf())、不可变包装(Collections.unmodifiableList())或新对象
3. 构造过程要防御性拷贝可变组件
如果类包含可变对象(如 java.util.Date、ArrayList、数组),必须在构造器中拷贝它们,避免外部传入的对象后续被修改影响本类状态。
示例(含防御性拷贝):
public class Event {
private final String title;
private final Date startTime; // java.util.Date 是可变的!
public Event(String title, Date startTime) {
this.title = Objects.requireNonNull(title);
// 防御性拷贝:不直接赋值 startTime
this.startTime = new Date(startTime.getTime());
}
public Date getStartTime() {
// 同样返回副本,防止外部修改
return new Date(startTime.getTime());
}
}
4. 类本身声明为 final(推荐)
防止子类通过继承破坏不可变性(例如重写方法、添加可变字段)。虽然不是绝对必需,但属于最佳实践。
- 加
final class Event { ... } - 或使用密封类(Java 17+)限制继承范围
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











