Skip to content

P46 面试重灾区:JVM 常量池与 intern() 的谎言 ​

面试题:字符串常量池是什么?new String("abc") 创建了几个对象?intern() 到底干什么?

1. 几个基础概念 ​

  • 字符串常量池(String Pool):存放字符串字面量和 intern 的字符串,JDK 7+ 移到堆中;
  • 字面量 "abc":编译期放入 class 文件常量池,类加载后放入运行时常量池/字符串常量池;
  • new String("abc"):运行时在堆里创建一个新对象。

2. 经典问题:new String("abc") 创建几个对象 ​

java
String s = new String("abc");

答案分情况:

  • "abc" 第一次出现:创建 2 个对象(字符串常量池里的 "abc" + 堆上的 new 对象);
  • "abc" 已在常量池:只创建 1 个对象(堆上的 new 对象)。

注意:两个对象的值相同但引用不同,s == "abc" 为 false。

3. intern() 到底是什么(视频说的"谎言") ​

java
String s = new String("abc");
String t = s.intern();  // 把 s 的值放进常量池,返回常量池引用

intern() 的行为:

  • 若常量池中已有相同内容的字符串 → 返回常量池中那个引用(堆里的 s 保持原样);
  • 若没有 → JDK7+ 会把 s 的引用登记到常量池(不是复制一份),并返回该引用。

4. 常见误区("谎言") ​

误区 1:"intern() 会在常量池中复制一份"

→ JDK 7 后,堆字符串 intern 时是把堆中对象的引用放进常量池,并没有复制出第二个字符串对象。

误区 2:"常量池里的字符串一定在方法区"

→ JDK 7 起字符串常量池已移到堆中(运行时常量池仍在方法区/元空间,但字符串常量池在堆)。

误区 3:"new String 一定创建两个对象"

→ 取决于字面量是否首次出现。

误区 4:"intern() 一定省内存"

→ 对大量重复且生命周期长的字符串,intern 能去重省内存;但如果字符串千变万化,常量池本身也会膨胀,还可能拖慢 GC。

5. 常见考题 ​

java
String a = "ab";
String b = new String("ab");
String c = b.intern();
System.out.println(a == b);   // false
System.out.println(a == c);   // true
System.out.println(b == c);   // false(b 还是堆对象)

一句话总结 ​

字符串常量池 JDK7+ 在堆中;new String("abc") 首次创建 2 个对象、否则 1 个;intern() 是"把引用登记进常量池并返回常量池引用",不是复制;理解这些才能答对 == 比较和内存语义。

基于 VitePress 重建