在 Java 中,**不可变对象(Immutable Object)**是指对象一旦创建,其状态(字段值)就不能再被修改。创建不可变对象是编写健壮、线程安全代码的重要手段。
下面是创建不可变 Java 对象的完整方法和示例。
要让一个对象不可变,通常需要遵守以下 5 条规则:
防止子类修改行为
→ 使用 final 修饰类
public final class Person {
}
private 和 finalprivate:防止外部直接访问final:保证对象创建后不可被重新赋值private final String name;
private final int age;
只允许通过构造方法初始化状态。
构造对象时必须提供完整状态。
这是最容易出错的地方。
public final class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
✅ 原因:
String 本身是不可变的int 天然不可变public final class Student {
private final Date birthDate;
public Student(Date birthDate) {
this.birthDate = birthDate;
}
public Date getBirthDate() {
return birthDate; // 外部可修改
}
}
外部可以这样破坏:
Date date = new Date();
Student s = new Student(date);
date.setTime(0); // 修改了 Student 内部状态
import java.util.Date;
public final class Student {
private final Date birthDate;
public Student(Date birthDate) {
this.birthDate = new Date(birthDate.getTime()); // 拷贝
}
public Date getBirthDate() {
return new Date(birthDate.getTime()); // 拷贝
}
}
✅ 确保:
private final List<String> list;
public List<String> getList() {
return list;
}
外部可以:
s.getList().add("hack");
import java.util.Collections;
import java.util.List;
public final class Group {
private final List<String> members;
public Group(List<String> members) {
this.members = new ArrayList<>(members);
}
public List<String> getMembers() {
return Collections.unmodifiableList(members);
}
}
import java.util.List;
public final class Group {
private final List<String> members;
public Group(List<String> members) {
this.members = List.copyOf(members);
}
public List<String> getMembers() {
return members;
}
}
当字段很多时使用 Builder 更加优雅。
public final class User {
private final String name;
private final int age;
private User(Builder builder) {
this.name = builder.name;
this.age = builder.age;
}
public static class Builder {
private String name;
private int age;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public User build() {
return new User(this);
}
}
}
使用方式:
User user = new User.Builder()
.name("Tom")
.age(20)
.build();
✅ 线程安全(无需加锁)
✅ 易于缓存
✅ 减少副作用
✅ 更安全、更易推理
StringInteger、Long 等包装类BigDecimalLocalDate、LocalDateTimeCollections.unmodifiableXXX如果你愿意,我可以:
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。