java中的不可变类(Immutable)

前言

在多线程并发编程中,为了保证对象状态的原子性、可见性和有序性,开发者通常会使用 synchronized 等同步机制。

然而,过多的同步不仅会增加代码复杂度,还会影响性能。

如果我们将类设计为不可变的,那么对象的状态自始至终都不会改变。

这样一来,每次需要修改状态时都会产生一个全新的对象供不同线程使用,从而从根本上消除了并发安全问题。

一、什么是不可变类

一个类的对象在通过构造方法创建后,如果其状态绝对不会再被改变,那么这个类就是不可变(Immutable)类。

不可变对象具有以下核心特征:

  • 所有成员变量的赋值操作仅在构造方法中完成。
  • 不对外提供任何 setter 方法,彻底切断外部类修改其内部状态的途径。

二、常见的不可变类

提到不可变类,Java中最经典的就是 String 类,此外还包括 IntegerLong 等基本数据类型的包装类。String 类被设计为不可变的,主要基于以下三个方面的考量:

  1. 常量池的需要

    字符串常量池是Java堆内存中的一个特殊存储区域。创建 String 对象时,如果该字符串在常量池中不存在,则新建一个;如果已存在,则直接复用已有的引用地址。这种机制能够大幅减少JVM的内存开销,提升运行效率。

  2. hashCode 缓存

    由于字符串状态不可变,在其创建之初 hashCode 就可以被计算并缓存起来。这使得 String 非常适合作为哈希表(如 HashMap)的键,多次调用只需返回同一个哈希值,极大地提高了检索效率。

  3. 线程安全

    不可变对象天然具备线程安全性。在多线程环境下共享 String 对象时,不会出现不可预期的结果,因此也无需进行额外的同步处理。即使我们调用 String 类的 trim()substring()toLowerCase() 等方法,原字符串对象依然完好无损,方法会返回一个经过处理的全新对象。

image-20260423224716740

三、代码实践

理解不可变类很容易,但手写一个严谨的自定义不可变类需要严格遵守以下四个条件:

  1. 确保类是 final 的:防止该类被其他类继承,从而避免子类重写方法破坏其不可变性。
  2. 确保所有的成员变量是 final 的:强制字段只能在构造方法中初始化,后续绝无法被修改。
  3. 不提供任何 setter 方法:关闭外部修改对象状态的入口。
  4. 如果包含可变对象,必须返回副本:这是最容易忽略的一点。如果不可变类内部持有其他可变类的对象(例如一个普通的 Book 类),在对外提供该对象的 getter 方法时,必须返回该对象的防御性副本,绝不能直接暴露其底层的引用地址。否则,外部代码可以通过该引用地址轻易篡改原对象的数据。

代码实现示例:

// 一个普通的可变类
public class Book {
    private String name;
    private int price;
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getPrice() { return price; }
    public void setPrice(int price) { this.price = price; }
}

// 自定义的不可变类
public final class Writer {
    private final String name;
    private final int age;
    private final Book book;

    public Writer(String name, int age, Book book) {
        this.name = name;
        this.age = age;
        this.book = book;
    }

    public String getName() { return name; }
    public int getAge() { return age; }

    // 核心点:必须返回内部可变对象的克隆副本,防止引用地址外泄
    public Book getBook() {
        Book clone = new Book();
        clone.setName(this.book.getName());
        clone.setPrice(this.book.getPrice());
        return clone;
    }
}

在上面的测试用例中,如果不采用防御性拷贝返回 clone 对象,外部对返回的 Book 进行 setPrice 操作时,就会破坏 Writer 类的不可变性。

image-20260423224730847

总结

不可变类通过牺牲极少量的内存(修改时需创建新对象),换取了多线程环境下的绝对安全。

在实际开发中,尤其是构建多线程高并发系统时,这种“无锁化”的设计思路极为重要

内容概要:本文系统梳理了多个科研领域的前沿研究与技术实现,重点涵盖FDTD方法中的完美匹配层(PML)研究,以及Matlab/Simulink在电磁、电力、控制、通信、信号处理、图像处理、路径规划、能源系统优化等领域的仿真与算法实现。文中列举了大量基于Matlab和Python的科研案例,如风电功率预测、负荷预测、无人机三维路径规划、电池系统故障诊断、雷达模拟、通信编码、微电网优化调度等,强调结合智能优化算法(如粒子群、遗传算法、深度学习等)提升系统性能。同时,提供了丰富的代码资源与仿真模型,涵盖永磁同步电机控制、逆变器设计、多智能体任务配、虚拟电厂调度等复杂系统,助力科研人员快速开展复现实验与创新研究。; 适合人群:具备一定编程基础,熟悉Matlab/Python工具,从事电气工程、自动化、通信、人工智能、新能源、控制科学等相关领域研究的研发人员及研究生。; 使用场景及目标:① 学习实现FDTD仿真中的PML边界条件以有效抑制数值反射;② 掌握Matlab/Simulink在多物理场建模、控制系统设计与优化算法中的综合应用;③ 借助提供的代码资源完成科研复现、课程设计、竞赛项目或工程原型开发; 阅读建议:此资源以科研实战为导向,不仅提供理论方法,更强调代码实现与仿真验证。建议读者结合自身研究方向,按目录顺序查阅相关模块,下载配套代码进行调试与二次开发,以达到学以致用、融会贯通的目的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值