What (本质)
- String不可变:对象创建后内容永不改变,所有"修改"操作返回新对象
- 字符串常量池:JVM在堆内存中维护的特殊共享池,存储字符串字面量,实现自动去重复用
💡 通俗比喻:
String → 刻在石头上的字(要改只能重刻一块石头)
常量池 → 图书馆的书籍仓库(相同的书只存一本,大家借阅同一本)
JVM → 智能图书管理员(自动检查库存,有就借,没有才买新书)
How(机制深度解析)
常量池工作流程
// 编译期 vs 运行期
String s1 = "hello"; // 编译期字面量 → 自动入池
String s2 = "hello"; // 复用池中对象 → s1 == s2 为 true
String s3 = new String("hello");// 运行期new → 堆中新建对象,**默认不入池**
String s4 = s3.intern(); // 手动入池 → 返回池中已存在的引用
System.out.println(s1 == s2); // true (常量池复用)
System.out.println(s1 == s3); // false (堆中不同对象)
System.out.println(s1 == s4); // true (intern()返回池中引用)
JVM内存布局演进
| JDK版本 | 常量池位置 | 原因 |
|---|---|---|
| JDK 6及以前 | 永久代(PermGen) | 与类元数据一起存储 |
| JDK 7+ | 堆内存(Heap) | 永久代空间有限,常量池易引发OOM,移至堆中更灵活 |
| JDK 8+ | 堆内存中的Metaspace外部 | 彻底移除永久代,常量池作为堆的一部分 |
Why(核心价值)
1. 内存优化(核心作用)
- 去重存储:1000个
"hello"只占1份内存 - 实测数据:10万次
"hello"创建- 无常量池:占用 ~8MB 堆内存
- 有常量池:占用 ~2MB 堆内存(节省75%)
- GC压力降低:减少对象创建,降低Young GC频率
2. 性能提升
- 引用比较优化:
==比较比equals()快100倍(常量池可控时) - 哈希缓存:String的
hash字段缓存计算结果,HashMap性能提升 - 类加载加速:类名、方法名等元数据字符串复用,加快类加载
3. 安全性保障
- 与不可变性协同:常量池依赖String不可变,否则一个修改会影响所有引用
- 防止内存攻击:避免恶意代码通过修改字符串破坏JVM核心机制