string不可变指对象内容无法更改,由final类、private final字段(char[]或byte[])及无写方法+防御性拷贝三重保障;支撑常量池复用、hashmap键稳定、线程安全与敏感信息防护。

Java 中的 String 不可变,不是指变量不能重新赋值,而是指字符串对象一旦创建,其内部存储的字符内容就无法被更改。你看到的“修改”,其实是让引用指向了一个新对象,原对象仍静静躺在内存里,没动过。
不可变是怎么实现的?
核心靠三重保障:
- 类被 final 修饰:String 类不能被继承,避免子类绕过限制增加修改能力
-
字符数组被 private final 修饰:JDK 8 是
private final char[] value,JDK 9+ 改为private final byte[] value,既封死了外部访问路径,又锁死了数组引用本身 -
无任何写方法 + 构造时防御性拷贝:String 不提供 set 方法;构造器接收外部 char[] 或 byte[] 时,会用
Arrays.copyOf拷贝一份,防止外部数组后续被篡改影响内部状态
为什么非要不可变?关键在四个实际场景
这不是教条设计,而是解决真实问题的必然选择:
-
字符串常量池能安全复用:比如
String a = "hello"; String b = "hello";,a 和 b 共享同一块内存。如果 String 可变,a 修改了内容,b 的值就“意外”变了——这显然不可接受 -
作为 HashMap 的 key 才可靠:String 的
hashCode()被缓存一次后终身有效。若内容可变,哈希值随之变化,key 就再也找不回对应的 value,哈希表直接失效 - 多线程环境天然安全:无需同步、无需加锁,多个线程读同一个字符串,完全不用担心它突然被别的线程改掉
- 敏感信息传递更安心:数据库连接串、密码、URL 参数等以 String 形式传入方法时,方法内部无法偷偷篡改原始值,从根源上堵住安全漏洞
常见误解澄清
很多人被下面这段代码迷惑:
String s = "abc";<br>s = "def";
这里改变的只是变量 s 的引用指向,不是字符串对象本身。“abc”对象依然存在,只是没人再指向它,最终被 GC 回收。“def”是全新创建的对象。就像把一张旧照片放进抽屉,再换一张新照片摆在桌面上——抽屉里的旧照没被涂改,只是你不再看它了。
那拼接、替换这些操作怎么来的?
所有看似“修改”的方法(如 concat、replace、substring)内部都做了同一件事:新建一个 String 对象。早期用 StringBuffer,后来优化为 StringBuilder 来构建新内容,最后包装成新的 String 实例返回。原对象全程未参与、未改动。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











