ITPub博客

首页 > 应用开发 > Java > Java 中如何设计一个不可变的类?

Java 中如何设计一个不可变的类?

原创 Java 作者:mingtian66 时间:2024-11-08 12:23:02 0 删除 编辑

在 Java 中创建一个不可变类(Immutable Class),意味着创建的对象一旦被实例化,就不能再被修改。这种类在多线程环境下非常有用,因为它们天生是线程安全的。下面是实现不可变类的一些重要设计步骤和示例代码。
不可变类的设计要点

    将类声明为 final:防止子类继承,从而防止子类改变不可变性。
    将所有字段设为 private 和 final:防止字段在类外被访问或修改,同时保证它们只被初始化一次。
    不提供任何字段的修改器(setter)方法:确保字段的值在对象创建后不可改变。
    在构造函数中初始化所有字段:在构造函数中进行初始化,确保所有字段都在对象创建时被赋值。
    如果字段是可变对象,提供防御性拷贝:如果类包含引用可变对象的字段(如 Date、List、Map 等),在构造函数和 getter 方法中应对这些对象进行拷贝,以防外部引用更改这些对象的内容。

不可变类的示例代码

以下是一个不可变的 Person 类的示例:

import java.util.Date;

public final class Person {
    private final String name;
    private final int age;
    private final Date birthDate;  // Date 是一个可变对象

    // 构造函数
    public Person(String name, int age, Date birthDate) {
        this.name = name;
        this.age = age;
        
        // 防御性拷贝 Date 对象,避免外部对其修改
        this.birthDate = new Date(birthDate.getTime());
    }

    // 仅提供 getter 方法,没有 setter 方法
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public Date getBirthDate() {
        // 返回 Date 对象的拷贝,防止外部修改
        return new Date(birthDate.getTime());
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + ", birthDate=" + birthDate + '}';
    }
}

说明

    final 关键字:Person 类被声明为 final,确保不会有子类对其不可变性进行破坏。
    私有且 final 的字段:name、age 和 birthDate 字段都被声明为 private final,保证它们在构造之后不会被修改。
    防御性拷贝:构造函数和 getBirthDate() 方法中使用防御性拷贝,避免直接引用可变对象 Date。这样,即使外部代码试图修改传入的 Date 对象,Person 类的内部状态也不会受到影响。

使用示例

import java.util.Date;

public class Main {
    public static void main(String[] args) {
        Date birthDate = new Date();
        Person person = new Person("Alice", 30, birthDate);

        System.out.println("Before modifying birthDate: " + person);

        // 尝试修改 birthDate
        birthDate.setTime(birthDate.getTime() - 1000000000);
        
        System.out.println("After modifying birthDate: " + person);

        // 尝试通过 getBirthDate() 修改
        Date obtainedDate = person.getBirthDate();
        obtainedDate.setTime(obtainedDate.getTime() - 1000000000);

        System.out.println("After modifying obtainedDate: " + person);
    }
}

输出

Before modifying birthDate: Person{name='Alice', age=30, birthDate=Sat Oct 09 13:46:40 IST 2021}
After modifying birthDate: Person{name='Alice', age=30, birthDate=Sat Oct 09 13:46:40 IST 2021}
After modifying obtainedDate: Person{name='Alice', age=30, birthDate=Sat Oct 09 13:46:40 IST 2021}

解释

    无论是修改传入的 birthDate,还是修改 getBirthDate() 获取到的日期对象,都不会影响 Person 对象的 birthDate 字段。
    这种设计确保了 Person 类的不可变性,即一旦创建 Person 对象,其状态便无法更改。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70040412/viewspace-3047462/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2024-08-07

  • 博文量
    589
  • 访问量
    603031