Java字符串创建方式决定内存位置与对象身份:字面量赋值复用常量池(s1=="abc"与s2=="abc"时s1==s2为true),new创建总在堆新建对象(s1=new String("abc")与s2=new String("abc")时s1==s2为false)。

Java 中字符串的创建方式直接影响内存分配位置和对象身份判断,关键在于区分字面量直接赋值与 new 关键字创建——前者优先尝试复用常量池中已存在的字符串,后者总在堆中新建对象。
字符串字面量自动入池:编译期确定的共享机制
使用双引号声明的字符串(如 "hello")在类加载阶段就被放入字符串常量池(JDK 7+ 位于堆中,JDK 6 在永久代)。JVM 会检查池中是否已有相同内容的字符串,若有则直接返回引用,否则新建并存入。
- 同一字面量多次出现,只生成一个对象,所有引用指向池中同一实例
-
String s1 = "abc"; String s2 = "abc";→s1 == s2为 true - 常量池中的字符串默认不可变,且由 JVM 自动管理生命周期
new String("abc") 的双重内存行为
该写法强制在堆中创建新对象,同时仍会触发常量池检查:若池中无 "abc",先将其加入池,再在堆中新建对象;若已存在,则跳过入池步骤,仅堆中新建。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 每次
new都产生独立堆对象,即使内容相同 -
String s1 = new String("abc"); String s2 = new String("abc");→s1 == s2为 false,但s1.equals(s2)为 true - 可显式调用
s1.intern()将其引用注册进常量池(若未存在),后续相同字面量将指向该对象
常量池扩容与 intern() 的实际影响
intern() 不是“把对象塞进池”,而是返回池中对应字符串的引用。若池中尚无该字符串,JDK 7+ 会将该字符串对象本身(即堆中实例)的引用存入池;JDK 6 则复制一份到永久代。
立即学习“Java免费学习笔记(深入)”;
-
String s = new String("xyz").intern();后,s == "xyz"为 true - 频繁调用
intern()可能引发常量池膨胀,尤其处理大量动态字符串时需谨慎 - 常量池大小可通过
-XX:StringTableSize调整,默认值通常足够,但高并发字符串去重场景下可能需优化
运行时常量池 vs 类文件常量池
类文件中存储的是编译期生成的符号引用(含字符串字面量),类加载后这些字面量被解析并存入运行时常量池。运行时常量池是每个类独有的,而字符串常量池是全局唯一的(JVM 级别)。
- 类文件常量池属于静态结构,不参与运行时内存分配
- 字符串常量池是运行时常量池的一部分,但专门用于字符串对象的共享管理
- 反射、动态代理等操作可能间接向运行时常量池添加内容,但字符串池只响应
ldc指令和intern()调用

















