java中string的==判等返回true的关键是两引用指向同一内存地址,而非内容相同;编译期可确定的字符串(如字面量、final变量拼接)入常量池复用,运行时生成的字符串(如变量拼接、new string)在堆中新建对象,故==为false;equals则比较内容,应优先用于业务判等。

Java 中 String 判等(==)是否返回 true,关键不在于“字符串内容是否相同”,而在于两个引用是否指向**同一块内存地址**。而这个地址是否一致,很大程度上取决于编译器能否在**编译期就确定字符串值**——能确定的,就放进字符串常量池并复用;不能确定的,就在运行时堆中新建对象。
哪些情况会被编译器优化进常量池?
只有满足“编译期可完全确定”的字符串表达式,才会被折叠为字面量,并共享常量池地址。典型包括:
- 纯字面量拼接:
"a" + "b"→ 编译后直接变成"ab",存入常量池 -
final修饰的字符串变量参与拼接:final String c = "a"; String d = c + "b";→d被优化为常量"ab" - 静态
final字段参与拼接:public static final String A = "x"; String s = A + "y";→ 同样优化为"xy"
哪些情况不会被优化,导致 == 判等失败?
只要存在任何“运行时才可知”的成分,编译器就放弃优化,拼接操作推迟到运行时执行(通常用 StringBuilder),结果对象分配在堆内存:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 普通局部变量参与拼接:
String a = "a"; String b = a + "b";→b是堆中新对象,b == "ab"为false - 方法调用结果参与拼接:
String e = getA() + "b";→ 即使getA()总返回"a",编译器也无法预知,不优化 -
new String("...")创建的对象:一定在堆中,与常量池中的同值字符串地址不同
intern() 是怎么介入判等逻辑的?
intern() 的作用是“主动把字符串注册进常量池,并返回池中已有或新加入的引用”。它让原本在堆里的字符串,有机会和常量池对齐:
-
String b = new String("ab");→b指向堆对象 -
String c = "ab";→c指向常量池 -
b.intern() == c→true(因为intern()返回的就是c的引用) -
b == c→false(原始引用不同)
实际开发中怎么安全判等?
除非你明确需要判断“是否同一个对象”(如缓存 key 引用一致性),否则永远优先用 .equals():
-
.equals()先快速判断引用相等(this == anObject),再逐字符比较内容,兼顾性能与语义 - 避免依赖
==做业务逻辑判断,尤其涉及用户输入、配置、网络响应等动态字符串时 - 若确需用
==提升性能(如大量固定枚举字符串匹配),可用intern()统一归一化,但需注意常量池内存压力
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










