字符串常量池在JDK 7+位于堆内存,编译期仅优化全字面量拼接(如"a"+"b"),new String("abc")先确保常量池存在"abc"再在堆新建对象;intern()查池后返回已有引用或存入当前对象引用。

直接看真题本身没用,关键要抓住三件事:常量池位置、对象创建时机、编译期能否优化。只要理清这三点,90%的字符串面试题都能秒答。
字符串常量池在哪?什么时候进池?
常量池在方法区(JDK 7+移到堆中),但逻辑上仍叫“字符串常量池”。它只收两类字符串:
- 所有双引号字面量,比如 "abc"、"hello" + "world"(编译期能算出结果的拼接)
- 显式调用 intern() 的字符串——前提是池里还没有相同内容的字符串,才会把该字符串对象引用存入池中
注意:new String("abc") 一定在堆里新建对象,但会先确保常量池有 "abc"(没有就放一个),所以最多创建两个对象。
== 和 equals 到底比什么?
== 比的是引用地址:两个变量是否指向同一块内存。
立即学习“Java免费学习笔记(深入)”;
- 字面量赋值(String s = "abc")→ 指向常量池
- new String("abc") → 指向堆中新对象
- 所以 s1 == s2 为 true,仅当它们都来自常量池,或其中一个 intern 后恰好命中另一个
equals() 比的是字符序列:String 重写了 equals,逐个比较 char 数组内容,跟内存位置无关。
哪些拼接会在编译期优化?哪些 runtime 才执行?
编译器只优化全由字面量构成的拼接,例如:
- "a" + "b" + "c" → 编译成 "abc",进常量池
- "ab" + 123(数字字面量)→ 也优化,因为 123 是编译期常量
但只要含变量(哪怕 final),就不优化:
- String a = "ab"; a + "c" → 运行时 new StringBuilder 拼,结果在堆里
- final String b = "ab"; b + "c" → JDK 8+ 会优化(因 b 是编译期常量),但非 final 变量一定不优化
intern() 方法到底干了什么?
intern() 不是“把字符串塞进常量池”,而是查池、选引用、返回地址:
- 如果池里已有相同内容的字符串 → 直接返回池中那个的引用
- 如果池里没有 → 把当前字符串对象的引用存入池,并返回这个引用(JDK 7+ 支持堆中对象入池)
典型陷阱题:
String s = new String("ab") + new String("c"); s.intern(); String t = "abc"; → s == t 是 true 还是 false?
答案是 true(JDK 7+),因为 s 构造出的 "abc" 对象在堆中,调用 intern 后池中无 "abc",于是把 s 的引用存入池;t = "abc" 就直接取池中引用,两者指向同一对象。


















