Java String常量池实现字符串复用,JDK 7+位于堆内存,字面量自动入池,new创建对象在堆中,需调用intern()手动入池;其哈希查找和同步机制带来性能开销,适用于大量重复且长生命周期字符串场景。

Java 中 String 类通过字符串常量池(String Pool)实现全局复用,本质是 JVM 在堆外(JDK 7+ 在堆内)维护的一块特殊内存区域,用于存储唯一值的字符串字面量。当代码中出现相同字符串字面量时,JVM 不会重复创建对象,而是复用已存在的引用。
字符串字面量自动入池
使用双引号直接定义的字符串(如 "hello")在类加载阶段就会被放入常量池。JVM 保证同一字面量只存一份。
-
编译期确定:如
String a = "abc"; String b = "abc";,a 和 b 指向常量池中同一个对象,a == b返回 true -
仅限字面量:带运行时计算的表达式(如
"ab" + "c"在编译期能优化为字面量,也会入池;但"ab" + new String("c")则不会
new String() 默认不入池,需手动 intern()
用 new String("abc") 创建的字符串对象一定在堆中,与常量池无关。但它内部的字符内容可能已存在于池中。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- intern() 方法作用:检查常量池中是否存在相同内容的字符串;若存在,返回池中引用;若不存在,将该字符串加入池并返回其引用
-
典型用法示例:
String s1 = new String("abc"); // 堆中新建对象 String s2 = s1.intern(); // 查池,发现已有"abc",返回池中引用 String s3 = "abc"; // 字面量,直接指向池中 s2 == s3 → true
常量池位置随 JDK 版本变化
常量池物理位置影响 GC 行为和内存管理方式:
立即学习“Java免费学习笔记(深入)”;
- JDK 6 及以前:常量池在永久代(PermGen),大小受限且不易调整
- JDK 7 起:常量池移到 Java 堆中,受堆内存参数控制(如 -Xmx),更灵活,也更容易被 GC 回收
- JDK 8+(无永久代):常量池仍在堆中,逻辑上属于“运行时常量池”,与类的其他元信息分离管理
注意 intern() 的实际开销与适用场景
虽然 intern() 能节省内存,但频繁调用有性能代价:
- 哈希查找成本:每次调用需在常量池中做字符串内容比对(基于 hashCode 和 equals)
- 线程安全开销:intern() 是同步方法,高并发下可能成为瓶颈
- 适合场景:读取大量重复字符串(如解析 CSV、JSON 中的字段名、枚举标识符),且生命周期长、复用率高

















