在 java 中实现不可变对象,核心做法是将类声明为 final,将所有字段设为 private final,并在构造函数中通过深拷贝初始化这些字段,同时不提供任何修改状态的 setter 方法。这样能确保对象一旦创建,其内部状态就无法被外部或子类更改。

如何防止可变集合导致的状态泄露?
当不可变对象包含可变引用类型(如 List)时,必须在构造函数中进行深拷贝,并在 getter 中也返回副本。如果不这样做,外部获取集合后直接修改内容,就会破坏对象的不可变性。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Person {
private final String name;
private final List<string> hobbies;
public Person(String name, List<string> hobbies) {
this.name = name;
// 防御性拷贝:防止外部传入的可变列表被修改
this.hobbies = new ArrayList(hobbies);
}
public String getName() {
return name;
}
public List<string> getHobbies() {
// 防御性拷贝:防止外部获取引用后修改内部数据
return Collections.unmodifiableList(hobbies);
}
}</string></string></string>
如何处理日期等复杂可变类型的不可变性?
对于 Date 等旧版可变类型,同样需要在构造函数中通过 new Date(date.getTime()) 进行克隆。如果使用 Java 8+ 的 LocalDate 等不可变类型,则可以直接赋值,但仍需保持 private final 和 final 类的约束以确保整体不可变。

import java.time.LocalDate;
import java.util.Date;
public class Event {
private final String title;
private final LocalDate date;
public Event(String title, LocalDate date) {
this.title = title;
this.date = date; // LocalDate 本身是不可变的,直接赋值安全
}
public String getTitle() {
return title;
}
public LocalDate getDate() {
return date;
}
}
为什么必须将类声明为 final?
如果类不是 final,子类可以继承该类并添加可变字段或重写 getter 来暴露内部状态,从而破坏不可变性契约。因此,声明 final 是保证不可变性的最后一道防线。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











