Java 字符串常量池是什么?String.intern()、字面量和 new String 有什么区别?
下面是一段教学用的模拟面试。
🧑💻 面试官:两个内容相同的字符串,用 == 比较一定是 true 吗?
🙋♂️ 我:不一定。== 比较引用,equals 比较字符串内容。
🧑💻 面试官:那两个 “CN” 字面量,为什么又能用 == 得到 true?
🙋♂️ 我:因为字符串常量池会复用它们。
🧑💻 面试官:如果其中一个来自 new String(“CN”),再调用 intern(),到底哪一个对象被复用了?
这道题要分开看两件事:「内容相同」和「引用相同」。常量池解决复用,业务比较仍然应该看内容。
面试速答(60 秒版)
Java 的字符串池会为相同内容保存一个规范的 String 对象。字符串字面量,以及值为字符串的常量表达式,会使用池里的对象。
而 new String("CN") 会创建一个新的 String 对象,所以它和字面量内容相同,引用却不一定相同。调用 intern() 后,如果池里已经有相同内容的字符串,就返回那个对象;如果没有,就把当前对象加入池并返回它。
因此,intern 并不是把原变量指向的对象直接改掉。只有接住它的返回值,才能拿到规范引用。
实际开发中,我们还是用 equals 比较内容。不要为了让 == 可用,就给所有字符串调用 intern。是否驻留,需要看重复程度、字符串数量和实际内存收益。

图:相同内容,不一定同一对象。
知识点详解:字符串相同,到底是哪一层相同?
先把变量、对象和字符串池分开
假设两个模块都要保存区域编码 CN。模块 A 直接使用字面量,模块 B 则从接口取得文本。业务上,我们关心的是两个区域编码是否相同;虚拟机还需要处理另一件事:这两段文本要不要共享同一个 String 对象。
变量里保存的是对象的引用。两个变量可以指向同一个对象,也可以各自指向一个内容相同的对象。== 判断前一种关系,equals 判断后一种关系。
字符串池可以理解为一份按内容寻找规范对象的登记表。但这只是帮助理解的比喻,不意味着每次创建 String 都要自动去这里登记。
字面量、new 和 intern 分别做了什么?
把几种常见写法放在一起看,区别就清楚了:
| 写法 | 得到的引用 | 判断依据 |
|---|---|---|
a = "CN"、b = "CN" | 相同的池内引用 | 字面量驻留 |
c = new String("CN") | 新对象的引用 | new 创建对象 |
d = c.intern() | 与 a 相同的规范引用 | 池里已存在 CN |
因此,a 与 c 用 == 比较是 false,用 equals 比较是 true;a 与 d 用 == 比较则是 true。c 本身不会因为调用了 intern 就自动改为池内引用。
这里也不能把 new 的例子简单背成“这一行一定创建两个对象”。字面量对应的对象可能早已存在。要问新增了几个对象,需要交代执行前的池状态,以及统计的是哪一段执行过程。
以上驻留和返回规则来自 String API;字面量的规范由 Java 语言规范 定义。

图:intern 返回引用,不改原变量。
字符串拼接,也要看能否在编译期确定
"C" + "N" 是常量表达式,它的结果可以在编译期确定,使用驻留后的 CN。
但是,如果 p 是运行时取得的普通变量,p + "N" 就不能因为当前 p 恰好等于 C,便认定结果一定是池内对象。运行时拼接产生的字符串,不能照搬字面量的引用结论。
final 也不是一句万能解释。final String p = "C" 可以是常量变量;但 final String p = readPrefix() 的值需要运行时获得,并不是相同的情况。
本题讨论的是 Java 的对象身份和语言规则,没有同一套 TypeScript 或 Python API。其他语言即使存在驻留优化,也不能拿来证明 Java 的行为。
为什么不把所有字符串都 intern?
回到区域编码的场景。如果只有少量固定编码,池内复用可能很合适;如果是随机请求 ID、用户输入和不断变化的长文本,驻留并不一定有明显收益,还会增加查找和管理成本。
应该先确认重复字符串是否真的占了大量内存,再用实际堆分析和负载测试判断收益。也不要把旧版本的“字符串池永远在某个固定内存区”作为通用答案,内存实现需要说明 JVM 和版本。
面试官继续追问
那我统一用 intern,再用 == 比较,行不行?
在保证双方都取得规范引用时,== 可以判断引用一致。但这会让业务正确性依赖每一条输入路径都做驻留。漏掉一个分支,就可能出现内容相同却判断不同的问题。对于普通字符串业务,equals 更直接。
intern 会修改 String 的内容吗?
不会。String 内容不可变,intern 返回的是规范对象引用,不是修改字符串内容的操作。
null 怎么比较?
如果调用方可能为 null,就不能直接调用它的 equals。可以明确判空,或者使用允许 null 的内容比较工具。这个问题与常量池没有关系。
面试速记卡
- ==:比较引用是否相同;equals:比较字符串内容。
- 字面量和字符串常量表达式:使用驻留后的对象。
- new String:创建新对象,内容相同不代表引用相同。
- intern:返回规范引用,不会替你修改原变量。
- 工程选择:先证明复用有收益,不把驻留当成业务比较的前提。
公司面试真题
这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。
浏览公司面试真题 →