所有字段都是 final
:所有字段都应该使用 final
修饰,这样它们在对象构造后就不能再被修改。
没有修改状态的方法:不可变类不提供任何修改字段值的方法。
构造函数完全初始化:所有字段必须在构造函数中完全初始化。
类声明为 final
:通常将类声明为 final
,防止子类继承和修改其行为。
只提供访问器方法(getter):提供访问字段值的 getter
方法,但没有对应的 setter
方法。
深度复制:如果类包含引用类型的字段(如对象),应确保这些对象本身也是不可变的,或者在构造函数中进行深度复制,防止外部对象的修改影响到不可变类的状态。
// 将类声明为 final,防止继承
public final class Person {
// 所有字段都使用 final 修饰
private final String name;
private final int age;
// 构造函数完全初始化所有字段
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 只提供 getter 方法,没有 setter 方法
public String getName() {
return name;
}
public int getAge() {
return age;
}
// 没有方法能修改对象的状态
}
在这个例子中,Person
类是不可变的。一旦创建 Person
对象后,它的 name
和 age
字段就不能再被修改。
线程安全:不可变对象本质上是线程安全的,因为它们的状态无法改变,因此不需要同步机制。
容易设计和使用:由于不可变对象不能被修改,所以使用起来更加简单,不会意外地被改变。
更好的缓存和复用:因为不可变对象不会改变,它们可以安全地被缓存和共享,例如在集合或作为常量使用。
故障安全性:由于不可变对象的状态不会改变,因此它们在出现异常时不需要回滚。
示例:
import java.util.Arrays;
public final class Student {
private final String name;
private final int[] grades;
public Student(String name, int[] grades) {
this.name = name;
// 深度复制数组,避免外部修改影响对象状态
this.grades = Arrays.copyOf(grades, grades.length);
}
public String getName() {
return name;
}
public int[] getGrades() {
// 返回数组的副本,避免外部修改
return Arrays.copyOf(grades, grades.length);
}
}
在这个例子中,Student
类中的 grades
数组是通过深度复制实现不可变性的,确保外部代码无法通过数组引用来改变 Student
对象的状态。
不可变类是 Java 编程中一种重要的设计模式,特别适用于需要线程安全、简化设计和维护的场景。通过使用 final
修饰符、深度复制和不提供状态修改方法,开发者可以创建真正不可变的对象。