string不可变性指对象内容创建后无法更改,所有“修改”均生成新对象;其通过private final字段、无修改方法、新建对象实现,保障线程安全、常量池复用、hashcode缓存及安全性。

因为String对象创建后内容无法更改,所有“修改”操作都生成新对象,所以多个线程读取同一个String实例时,既不会相互干扰,也不需要加锁——线程安全是不可变性自然带来的结果,不是靠同步机制实现的。
不可变性体现在哪儿
Java中String类用private final修饰内部存储(JDK 8是char[] value,JDK 9+是byte[] value),这意味着:
- value字段引用不可重新赋值
- 数组内容对外不可修改(String不提供任何public方法改变它)
- concat、substring、replace等方法都新建数组、复制内容、返回新String对象
- 原对象状态从构造起就彻底固定
线程安全不是“被保证”,而是“不可能被破坏”
没有写操作,就没有竞态条件。多个线程同时访问同一String实例时:
- 读到的内容始终一致,无需volatile或synchronized
- 比如10个线程共用
String url = "jdbc:mysql://localhost/db",谁都改不了它 - 日志框架接收String参数时,不用做防御性拷贝,传入即可靠
- 对比StringBuilder:多线程共用必须手动加锁,否则结果不可预测
不可变性支撑关键机制稳定运行
如果String可变,Java核心机制会立刻崩塌:
- 字符串常量池失效:String a = "hello"; String b = "hello"; 本应指向同一对象;若a改了内容,b也会“意外变化”
- HashMap键丢失:String作为key时,hashCode首次调用后缓存;内容一变,哈希值就变,导致key在桶里“消失”
- 安全风险放大:数据库密码、文件路径、HTTP URL以String传递,不可变确保中间方法无法篡改
注意:变量可变 ≠ 对象可变
常见误解来自混淆引用和对象:
-
String s = "a"; s = "b";——只是让s指向新对象,“a”仍存在且未变 - 真正检验不可变性,要看对象自身能否被任何public途径修改:答案是否定的
- 反射虽能绕过限制修改value,但属非法操作,破坏JVM契约,生产环境严禁使用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











