string不可变性指其内部字符数组被final修饰且修改方法均返回新对象,从而保障哈希值稳定、线程安全及字符串常量池的可靠复用。

Java中String的不可变性不是语法限制,而是设计选择——它让字符串对象一旦创建就不能被修改,这个特性直接支撑了字符串常量池(String Pool)的内存优化机制。
String不可变性的本质是什么
不可变性指String类内部用final char[](Java 8及以前)或final byte[](Java 9+)存储字符数据,且所有可能改变内容的方法(如substring、toLowerCase、concat)都返回新String对象,而非修改原对象。这意味着:
- 同一个String实例的哈希值在生命周期内恒定,可安全缓存(
hash字段懒计算) - 无需担心多线程并发修改,天然线程安全
- JVM可以放心地在常量池中复用相同内容的String引用
字符串常量池如何利用不可变性做优化
常量池是堆中一块特殊区域(Java 7起移至堆内存),用于存放编译期确定的字符串字面量和运行期显式入池的字符串。不可变性保证了池中每个String都是“只读可信”的:
-
编译期优化:代码中写
String a = "hello"; String b = "hello";,JVM在类加载阶段就将两个字面量指向常量池中同一个对象 -
运行期节省:调用
"abc".intern()时,若池中已存在"abc",直接返回其引用;否则将当前字符串加入池并返回——这依赖于内容不可篡改,否则复用会出错 - 避免意外污染:如果String可变,一个线程修改了池中某个字符串,其他所有引用它的变量都会受影响,后果不可控
new String("abc")为什么绕过常量池?
new String("abc")一定在堆中新建对象,即使"abc"已在常量池中存在。这是因为new强制调用构造器,在堆上分配空间,与常量池无关。但注意:
-
"abc"本身仍会进入常量池(如果尚未存在) -
new String("abc").intern()在首次调用时,会把堆中这个字符串的引用放入常量池(Java 7+) - 对比:
==比较的是引用地址,所以new String("abc") == "abc"为false;而.equals()比较内容,结果为true
实际开发中要注意什么
理解不可变性和常量池,能帮你写出更高效、更安全的代码:
- 拼接少量固定字符串优先用字面量(
"a" + "b"),编译器会自动优化为"ab"并入池 - 大量动态拼接用
StringBuilder,避免产生一堆无用的中间String对象 - 从数据库或网络读取的字符串,如需频繁作为key使用(如Map键、switch case),可考虑调用
intern()减少内存占用——但要权衡GC压力和池大小 - 不要试图通过反射修改String内容,虽然技术上可行,但会破坏JVM信任模型,导致不可预知行为
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











