java中string内存分配核心是常量池与堆分工:字面量赋值复用常量池对象,new强制在堆新建对象;前者s1==s2为true,后者s1==s2为false;intern可将堆对象加入常量池实现引用统一。

Java 中 String 的内存分配方式,核心在于理解字符串常量池(String Pool)和堆(Heap)的区别。直接量赋值和 new 关键字创建 String 对象,会触发不同的内存分配路径,直接影响对象的引用关系和 == 判断结果。
直接量赋值:优先复用字符串常量池
当你写 String s = "hello";,JVM 会执行以下步骤:
- 先检查字符串常量池中是否已存在内容为
"hello"的对象; - 如果存在,直接返回该对象的引用(不新建);
- 如果不存在,则在常量池中创建该字符串,并返回其引用。
这个过程是自动的、不可见的,且常量池位于方法区(JDK 7+ 后移至堆中,但逻辑上仍视为独立区域)。所有相同字面量的直接赋值,通常指向同一个常量池对象。
new String("hello"):一定在堆中新建对象
使用 new 创建时,无论常量池中是否存在对应字符串,JVM 都会在堆中分配一个全新的 String 对象:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 首先确保常量池中有
"hello"(若无则放入),这步和直接量一样; - 然后在堆中调用 String 构造器,复制常量池中的字符内容,生成新对象;
- 返回的是堆中这个新对象的引用,与常量池中的对象不是同一个。
例如:String a = "hello";String b = new String("hello");a == b 为 false(引用不同),但 a.equals(b) 为 true(内容相同)。
注意 intern() 方法的作用
intern() 是 String 类的一个 native 方法,用于手动将堆中字符串“登记”进常量池:
- 若常量池已有相同内容字符串,返回其引用;
- 否则,将该字符串加入常量池,并返回其引用。
所以:String c = new String("hello").intern();c == "hello" 为 true,因为 c 现在指向常量池中的对象。
面试高频陷阱点
-
"ab" + "c"在编译期能确定结果,等价于"abc",走常量池; -
String a = "ab"; String b = "c"; String c = a + b;是运行期拼接,结果在堆中(除非用final修饰变量让编译器优化); - JDK 7 及以后,字符串常量池从永久代移到堆空间,但语义不变;
-
String.valueOf(null)返回字符串"null",不是 null 引用,不会 NPE。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










