JavaSE-字符串-String不可变?

34 阅读2分钟

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核心机制