如何在Java中创建不可变类?

如果对象的状态在构造后无法更改 , 则该对象是不可变的 。不可变的对象不会让其他对象修改其状态 。对象的字段在构造函数内部仅初始化一次 , 以后再也不会更改 。
在本文中 , 我们将定义在JAVA中创建不可变类的典型步骤 , 并阐明开发人员在创建不可变类时遇到的常见错误 。
1.不可变类的用法
如今 , 每个软件应用程序的“必备”规范都将被分发和使用多线程 。多线程应用程序总是使开发人员感到头疼 , 因为要求开发人员保护其对象的状态 , 以防止同时修改多个线程 。同时 , 为此 , 开发人员通常在修改对象状态时使用“ 同步”块 。
对于不可变的类 , 状态永远不会被修改 。状态的每次修改都会产生一个新实例 , 因此每个线程将使用不同的实例 , 并且开发人员不必担心并发修改 。
2.一些流行的不可变类
字符串 是Java中最流行的不可变类 。初始化后 , 其值将无法修改 。操作像修剪() , 子串() , 替换()总是返回一个新的实例 , 并不会影响当前的实例 , 这就是为什么我们通常所说的修剪()  , 如下所示:
String alex = "Alex";
alex = alex.trim();
JDK的另一个示例是包装器类 , 例如:Integer , Float , Boolean……这些类不会修改其状态 , 但是 , 每次您尝试对其进行修改时 , 它们都会创建一个新实例 。
Integer a =3;
a += 3;
调用+ = 3之后 , 将创建一个新实例 , 其值保持为:6 , 并且第一个实例丢失 。
3.我们如何创建一个不可变的类
为了创建一个不可变的类 , 您应该遵循以下步骤:
1.
将您的班级定为最终班 , 以便其他班级无法对其进行扩展 。
2.
3. 将所有字段定为最终字段 , 以使它们在构造函数中仅初始化一次 , 之后再也不会修改 。
4. 不要公开setter方法 。
5. 在公开修改类状态的方法时 , 必须始终返回该类的新实例 。
6. 如果该类包含一个可变对象:
1. 在构造函数内部 , 请确保使用传递的参数的克隆副本 , 并且切勿将可变字段设置为通过构造函数传递的真实实例 , 这是为了防止传递对象的客户端事后对其进行修改 。
2. 确保始终返回该字段的副本 , 而不返回真实对象实例 。
3.1简单不可变类
让我们按照上述步骤操作 , 并创建自己的不可变类(ImmutableStudent.java) 。
package com.programmer.gate.beans;
public final class ImmutableStudent {
private final int id;
private final String name;
public ImmutableStudent(int id, String name) {
this.name = name;
this.id = id;
}
public int getId() {
return id;
public String getName() {
return name;
}
上面的类是一个非常简单的不可变类 , 它不包含任何可变对象 , 并且从不以任何方式公开其字段;这些类型的类通常用于缓存 。
3.2将可变对象传递给不可变类
现在 , 让我们的示例复杂一点 , 我们创建一个名为Age的可变类 , 并将其作为字段添加到ImmutableStudent中:
public class Age {
private int day;
private int month;
private int year;
public int getDay() {
return day;
public void setDay(int day) {
this.day = day;
public int getMonth() {
return month;
public void setMonth(int month) {
this.month = month;
public int getYear() {
return year;
public void setYear(int year) {
this.year = year;
private final Age age;
public ImmutableStudent(int id, String name, Age age) {
this.name = name;
this.id = id;
this.age = age;
return id;
return name;
public Age getAge() {
return age;
因此 , 我们在不可变类中添加了类型为Age的新可变字段 , 并在构造函数中按常规分配了该字段 。
让我们创建一个简单的测试类 , 并验证ImmutableStudent是否不再不可变:
public static void main(String[] args) {
Age age = new Age();
age.setDay(1);
age.setMonth(1);
age.setYear(1992);
ImmutableStudent student = new ImmutableStudent(1, "Alex", age);


推荐阅读