深入理解不可变对象

不可变对象在创建后其状态无法改变,如Java中的String类。String被设计为final且其内部字符数组是final的,确保其不可变性。不可变对象带来安全性,节省空间(字符串常量池),提高性能(哈希操作)以及线程安全等优势。在多线程环境中,不可变对象尤其重要,因为它们可以被共享而无需担心并发修改问题。
摘要由CSDN通过智能技术生成

前言

说到不可变对象,想必大部分人都不会陌生。Java程序员在日常开发过程中100%会用到的 String 对象就属于不可变对象吗,今天我们就来聊聊不可变对象这个话题。

什么是不可变对象

《Effective Java》中是这样定义不可变对象的:

不可变对象(Immutable Object):对象一旦被创建后,对象所有的状态及属性在其生命周期内不会发生任何变化。

简单的说,就是一个对象在创建后,不能对该对象进行任何更改。比如下面这段代码:

public class ImmutableObject {
    private int value;
     
    public ImmutableObject(int value) {
        this.value = value;
    }
     
    public int getValue() {
        return this.value;
    }
}

因为 ImmutableObject 不提供任何 setter 方法,并且成员变量 value 是基本数据类型,getter 方法返回的是 value 的拷贝,所以一旦 ImmutableObject 实例被创建后,该实例的状态无法再进行更改,因此该类具备不可变性。

String类

我们常见的String类,为什么说字符串是不可变的?我的代码中经常改变String的值啊!如下所示:

String string = "ABC";
string = string.concat("DE");

这样,上面的字符串不就改变成"ABCDE"了么?但是实际上,我们得到的已经是一个新的字符串。 alt

程序会在堆中重新创建一个"ABCDE"字符串,和"ABC"并不是同一个对象。

所以,一旦一个string对象在内存(堆)中被创建出来,他就无法被修改。而且,String类的所有方法都没有改变字符串本身的值,都是返回了一个新的对象。

string类如何设计成不可变
  1. String 类被 final 关键字修饰,所以它不会有子类,这就意味着没有子类可以重写它的方法,改变它的行为。
  2. String 类的数据存储在 char[] 数组中,而这个数组也被 final 关键字修饰了,这就表示 String 对象是没法被修改的,只要初始化一次,值就确定了。

不可变的好处

安全性

String 是 Java 中最基础也是最长使用的类,经常用于存储一些敏感信息,例如用户名、密码、网络连接等。因此,String 类的安全性对于整个应用程序至关重要。

节省空间(字符串常量池)

通过使用常量池,内容相同的字符串可以使用同一个对象,从而节省内存空间。如果 String 是可变的,试想一下,当字符串常量池中的某个字符串对象被很多地方引用时,此时修改了这个对象,则所有引用的地方都会改变,这可能会导致预期之外的情况。

性能

String 被广泛应用于 HashMap、HashSet 等哈希类中,当对这些哈希类进行操作时,例如 HashMap 的 get/put,hashCode 会被频繁调用。

线程安全

String 对象是不可修改的,如果线程尝试修改 String 对象,会创建新的 String,所以不存在并发修改同一个对象的问题。

由于不可变性,String 的 hashCode 只需要计算1次后就可以缓存起来,因此在哈希类中使用 String 对象可以提升性能。

总结

由于字符串是不可变的,因此它们的引用可以被视为普通变量,可以在方法之间和线程之间传递它们,而不必担心它所指向的实际字符串对象是否会改变。

本文由 mdnice 多平台发布

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值