java中string不可变的核心目的是支持安全复用、高效缓存与可靠共享:常量池复用相同字面量避免重复对象,jdk9+通过byte[]+coder实现ascii字符串内存减半,哈希值缓存提升hashmap性能,拼接需用stringbuilder规避gc压力。

Java 中 String 设计为不可变,核心不是为了“禁止修改”,而是为了让字符串能被安全复用、高效缓存、可靠共享——所有内存优势都建立在这个前提之上。
常量池复用:避免重复对象堆积
双引号字面量(如 "hello")在编译期就进入字符串常量池。JVM 每次遇到相同字面量,直接返回池中已有引用,不新建对象。
-
String a = "test"; String b = "test"; →
a == b为 true,说明共用同一块内存 - new String("test") 总是在堆中新建对象,哪怕池里已有相同内容
- "test".intern() 可主动将堆中字符串纳入常量池,或获取池中已有引用
紧凑存储:JDK9+ 内存减半
JDK9 起,String 内部从 char[] 改为 byte[] + coder。对纯 ASCII 字符(英文、数字、符号),每个字符只占 1 字节,内存占用下降约 50%。
- 该优化完全透明,代码无需改动
- 含中文等非 ASCII 字符时自动回退为 2 字节/字符,无兼容风险
- 不可变性保障了这种动态编码切换的安全性——内容不变,结构才敢适配
哈希值缓存:一次计算,长期复用
String 内部用 private int hash 缓存哈希值。因内容永不改变,首次调用 hashCode() 后即固定,后续直接返回。
- 作为
HashMap的 key 时,避免每次查找都重新计算 hash - 在配置项缓存、路由表等大量字符串 key 场景中,性能提升显著
- 若 String 可变,hash 值变动会导致 key “消失”在 map 中,引发数据错乱
拼接场景需主动规避 GC 压力
不可变性带来复用优势,但也意味着“修改即新建”。频繁拼接会生成大量临时对象,加重 GC 负担。
- 简单拼接(≤3 个字符串)用 + 即可,编译器自动优化为 StringBuilder
- 循环内拼接、动态构建长字符串,必须用 StringBuilder(单线程)或 StringBuffer(多线程)
- JDK7+ 的 substring 已改为复制子串,不再共享原数组,更安全但略有开销
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











