java中string字面量自动入常量池,new创建总在堆新建对象;x==y为false,x.equals(y)和x.intern()==y为true;intern()查池入池返引用,jdk7+池在堆中,频繁调用易致哈希冲突。

Java 中创建 String 对象看似简单,但背后涉及常量池、堆内存、类加载和引用关系多个层面。理解清楚,才能避开 == 判断错误、内存浪费、GC 压力等实际问题。
字面量创建:自动走常量池
写 String s = "hello"; 时,JVM 在编译期就把 "hello" 存进 class 文件的常量池;运行时,首次遇到该字面量会检查字符串常量池(StringTable)中是否已有内容相同的字符串:
- 有,则直接返回池中对象的引用;
- 没有,则在堆中新建 String 对象,并将其放入字符串常量池,再返回引用。
所以 String a = "abc"; String b = "abc"; 中,a == b 为 true —— 它们指向同一个池内对象。
new 创建:绕过池,只在堆里造新对象
String s = new String("abc"); 会强制在堆中创建一个全新对象,无论常量池里有没有 "abc":
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 如果池中尚无 "abc",JVM 先把字面量 "abc" 加入池,再在堆中 new 出一个副本;
- 如果池中已有 "abc",就只在堆中 new,不重复入池。
因此 String x = new String("abc"); String y = "abc"; 中,x == y 恒为 false(地址不同),但 x.equals(y) 和 x.intern() == y 都是 true。
intern() 是连接堆与池的“手动开关”
String.intern() 的作用很明确:查池、入池、返引用。
- 若池中已存在内容相同的字符串,直接返回池中那个引用;
- 若不存在,就把当前字符串内容复制一份加入池,并返回新加入对象的引用。
JDK7 起,字符串常量池移到堆内存中,所以 intern() 返回的就是堆内的对象引用,不再是永久代里的特殊地址。这意味着 new String("test").intern() == "test" 总是成立。
日常开发要注意的几个关键点
常量池不是万能缓存,用错反而伤性能:
- 永远别用
==比较两个 String 的内容,除非你确定它们都来自字面量或已调用intern(); - 避免对动态生成的字符串(如 JSON 字段、日志 ID)频繁调用
intern(),容易导致哈希冲突加剧、扩容开销大; - 可通过
-XX:StringTableSize=60013调整池大小,默认是 1009(JDK7/8 早期),过小会显著降低查找效率; -
new String(byte[])或new String(char[])不触发常量池检查,数组内容不会自动入池。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










