字面量赋值自动复用常量池中唯一实例,如String a="user"; String b="user";时a==b为true;new String("user")强制堆新建对象,应避免;内容比较一律用equals(),仅当确认同池引用时才用==。

直接用字面量赋值,避免 new;需要复用动态字符串时再谨慎调用 intern();比较内容一律用 equals(),只在确认同池引用时才用 ==。
字面量赋值自动复用,是默认最优路径
只要字符串内容在编译期确定,就应写成 String s = "abc" 形式。JVM 在类加载时就把该字面量注册进常量池(堆中),后续所有相同字面量都指向同一对象。
- String a = "user"; String b = "user"; → a == b 为 true,内存只存一份
- 日志级别、HTTP 方法、状态码等固定字符串,天然适合这种方式
- 避免写 new String("user") —— 它强制在堆新建对象,哪怕池里已有,也白占内存和 GC 压力
new 创建的字符串需显式入池才可共享
运行期生成的字符串(如从配置读取、数据库查出)无法走字面量路径,但若重复率高,可用 intern() 主动拉入常量池。
- String s1 = new String("ACTIVE").intern(); String s2 = "ACTIVE"; → s1 == s2 为 true
- intern() 在 JDK7+ 是轻量操作:只存引用,不拷贝内容;池中已有时直接返回原引用
- 适用场景明确:高频、固定、低变化的字符串,例如枚举标识、协议字段名、缓存 key 前缀
== 和 equals() 的使用边界必须分清
== 比较的是引用是否指向同一内存地址,它只在双方都来自常量池(或都经 intern())时才有意义;equals() 才是语义上“内容相等”的正确方式。
- String x = "OK"; String y = new String("OK"); → x == y 为 false,但 x.equals(y) 为 true
- 若误用 == 判断 new 出来的字符串,极易导致逻辑错误(如权限校验跳过)
- 只有当你明确控制了两边都出自常量池(比如全用字面量,或都调过 intern()),== 才可安全用于性能敏感路径
注意 intern() 的实际代价与风险
它不是免费午餐:每次调用都要哈希查找、可能触发扩容、入池后对象更难被 GC 回收。
- 禁止对 UUID、时间戳、用户输入、循环拼接串(如 "id_" + i)调用 intern()
- 可通过 JVM 参数 -XX:StringTableSize=120026 调大池容量,减少哈希冲突(默认 60013)
- 长期运行服务中,建议监控字符串池使用率(jstat -gc 或 JMX 中 StringTable 相关指标)

















