intern()本质是引用登记而非对象搬运:jdk7+常量池在堆中,未命中时直接登记堆中已有对象引用并返回,不复制内容;字面量与new字符串调用intern()后可==,因指向同一堆对象。

当调用 intern() 时,JVM 并不是“把字符串复制进常量池”,而是根据 JDK 版本决定如何记录引用——关键在于:从 JDK 7 开始,字符串常量池本身就在堆中,它存储的不是字符串对象副本,而是对**堆中已有字符串对象的引用**。
常量池找不到时,intern() 实际做了什么
以 JDK 8/11/17 等主流版本为例(即常量池位于堆内存):
- JVM 先在字符串常量池(StringTable)中查找是否已有内容相同的字符串引用
- 若未找到,JVM 不会新建对象,而是将当前字符串对象(已在堆中存在)的引用,直接存入常量池
- 然后返回这个刚存入的引用——它和原对象指向堆中同一块内存
也就是说,“找不到”不等于“创建新对象”,而是“登记现有堆对象的地址”。所以你看到 s1.intern() == s1 为 true,是因为 intern 返回的就是 s1 自己在堆中的那个引用。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
为什么字面量 "abc" 和 new String("abc").intern() 能 ==
因为两者最终都指向堆中同一个字符串对象:
-
String s1 = "abc":JVM 在加载类时就将 "abc" 字面量放入常量池,并在堆中创建对应 String 对象(value 数组也指向堆中字符数据),常量池条目记录该对象引用 -
String s2 = new String("abc"):在堆中新分配一个 String 对象,但其内部 char[] 通常复用字面量的底层数组(JDK 7+ 优化) -
s2.intern():发现常量池已有 "abc" 引用,直接返回该引用 → 指向和 s1 相同的堆对象
注意:不是所有 new 出来的字符串都能通过 intern() 和字面量相等
只有当字符串内容完全一致、且未被其他逻辑干扰时才成立。例如:
-
new String("a") + new String("b")构造出的 "ab" 最初不在常量池,调用 intern() 后才会登记堆中该对象的引用 - 如果该拼接结果恰好和某个已存在的字面量 "ab" 内容相同,intern() 就返回字面量对应的堆对象引用(不是拼接对象本身)
- 这时
(new String("a")+new String("b")).intern() == "ab"是 true,但和原拼接对象==是 false
小结:intern() 的本质是引用登记,不是对象搬运
它不移动数据,也不复制字符串内容;它只是在常量池里记一笔:“这个值,现在由堆中这个地址的对象代表”。只要堆中那个对象还活着,常量池条目就有效;一旦该对象被 GC 回收(且无其他强引用),对应常量池条目也可能被清理(JDK 17+ 默认 GC 可回收无强引用的 StringTable 条目)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










