字面量赋值只在常量池中创建或复用对象,new String()强制在堆中新建对象且可能额外在常量池创建一份;前者复用高效,后者地址唯一但开销大。

Java中 String 字面量(如 String s = "abc")和 new String("abc") 的内存分配方式完全不同,核心在于是否复用字符串常量池,以及对象创建的位置和数量。
字面量声明:只在常量池中操作
使用双引号直接赋值时,JVM 会先检查字符串常量池(位于方法区)中是否存在相同内容的字符串:
- 如果已存在,直接让变量引用池中那个对象,不创建新对象;
- 如果不存在,则在常量池中创建一个,并让变量引用它;
- 整个过程不会在堆中生成 String 实例;
- 多个相同字面量变量(如
s1 = "abc"、s2 = "abc")指向同一个常量池对象,所以s1 == s2为 true。
new String():强制在堆中新建对象
每次调用 new String("abc") 都会在堆内存中创建一个全新的 String 对象:
- 无论常量池里有没有
"abc",堆中一定新增一个对象; - 如果常量池中尚无该字符串,还会额外在常量池中创建一份(即最多创建两个对象);
- 每个
new出来的对象地址不同,所以s3 == s4(两者均为new String("abc"))结果是 false; - 但它们的内容一致,因此
s3.equals(s4)返回 true。
栈、堆、常量池各司其职
变量本身(如 s)存于栈中,它只是一个引用:
立即学习“Java免费学习笔记(深入)”;
- 字面量方式下,这个引用指向方法区的字符串常量池;
-
new方式下,这个引用指向堆中的新 String 实例,而该实例内部又持有对常量池中字符内容的引用(底层通过 value 数组共享); - 常量池不是堆的一部分,它是方法区(JDK 7+ 后移到堆中,但逻辑仍独立管理)中专门用于存储唯一字符串字面量的区域。
实际开发中怎么选
绝大多数场景应优先使用字面量声明:
- 节省内存,避免无意义的对象冗余;
- 提升性能,减少 GC 压力;
- 符合 Java 字符串不可变的设计意图;
-
new String()几乎只在极少数特殊需求下才需要,比如明确要求与常量池对象“物理隔离”(例如某些安全校验或反射绕过场景),日常业务代码中基本不需要。


















