温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java不可变类如何设计

发布时间:2026-07-16 10:00:53 来源:亿速云 阅读:91 作者:小樊 栏目:编程语言

在 Java 中,不可变类(Immutable Class)对象一旦创建,其状态(字段值)就不能再被修改。设计不可变类是并发安全和代码可维护性的重要手段。

下面从设计原则、示例、常见注意点、JDK 示例几个方面说明。


一、不可变类的设计原则

✅ 1. 不提供 setter 方法

  • 所有字段都是 private final
  • 不提供任何可以修改对象状态的方法

✅ 2. 类本身用 final 修饰

  • 防止被子类继承并重写行为,破坏不可变性
public final class ImmutableClass

✅ 3. 字段使用 final

  • 确保对象创建后字段只能被赋值一次
private final int value;

✅ 4. 通过构造方法初始化所有字段

  • 不提供默认构造器(或默认构造器不被外部使用)

✅ 5. 如果字段是引用类型,必须防御性拷贝

  • 防止外部修改内部引用对象
  • 尤其是集合、数组、自定义对象

✅ 6. 不返回可变内部对象的引用

  • 返回副本或不可变视图

二、一个标准不可变类示例

✅ 基础不可变类

public final class User {
    private final String name;
    private final int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

✅ 特点:

  • 无 setter
  • 字段 final
  • final

三、包含引用类型字段的不可变类(重点)

❌ 错误示例(存在可变性风险)

public final class User {
    private final Date birthDate;

    public User(Date birthDate) {
        this.birthDate = birthDate;
    }

    public Date getBirthDate() {
        return birthDate; // ⚠️ 外部可修改
    }
}
User user = new User(new Date());
user.getBirthDate().setTime(0); // 修改内部状态

✅ 正确写法(防御性拷贝)

import java.util.Date;

public final class User {
    private final Date birthDate;

    public User(Date birthDate) {
        this.birthDate = new Date(birthDate.getTime());
    }

    public Date getBirthDate() {
        return new Date(birthDate.getTime());
    }
}

四、包含集合字段的不可变类

✅ 使用不可变集合(推荐)

import java.util.List;
import java.util.Collections;

public final class Group {
    private final List<String> members;

    public Group(List<String> members) {
        this.members = Collections.unmodifiableList(
            new ArrayList<>(members)
        );
    }

    public List<String> getMembers() {
        return members;
    }
}

✅ Java 9+ 推荐写法

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 Person {
    private final String name;
    private final int age;
    private final String address;

    private Person(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.address = builder.address;
    }

    public static class Builder {
        private String name;
        private int age;
        private String address;

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

        public Builder address(String address) {
            this.address = address;
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }
}

使用:

Person p = new Person.Builder()
        .name("Tom")
        .age(20)
        .address("Beijing")
        .build();

六、不可变类的优点

线程安全

  • 无需加锁

缓存友好

  • 可安全共享对象

易于推理

  • 状态不会变化

适合作为 Map 的 key

  • StringInteger 都是不可变类

七、JDK 中的不可变类示例

说明
String 字符串不可变
Integer 包装类
BigDecimal 数值计算
LocalDate 时间 API
List.of() 不可变集合

八、总结一句话

不可变类 = final 类 + final 字段 + 无 setter + 防御性拷贝 + 不暴露可变引用

如果你愿意,我也可以帮你:

  • 分析某个类是否“真不可变”
  • 把可变类重构成不可变类
  • 对比不可变类 vs 写时复制(Copy-On-Write)
向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI