
本文详解 Java 中字符串 == 运算符的真实行为——它比较的是对象引用(内存地址),而非内容;重点剖析字符串常量池、编译期优化与运行时对象创建机制如何共同决定 == 的结果。
本文详解 java 中字符串 `==` 运算符的真实行为——它比较的是对象引用(内存地址),而非内容;重点剖析字符串常量池、编译期优化与运行时对象创建机制如何共同决定 `==` 的结果。
在 Java 中,== 运算符对引用类型(如 String)执行引用比较(reference comparison),即判断两个变量是否指向堆内存中的同一块地址。这与 equals() 方法的语义截然不同——后者比较的是字符串内容是否相等。理解 == 的行为,关键在于掌握 Java 的字符串常量池(String Pool)机制和对象创建方式。
✅ 字符串常量池:编译期优化的核心
当使用字面量方式声明字符串(如 String s = "Object";),JVM 会将该字符串自动 intern 到常量池中。若常量池中已存在相同内容的字符串,则直接复用其引用,不会新建对象。这就是为什么以下比较返回 true:
String str1 = "Object"; String str2 = "Object"; String str6 = "Obj" + "ect"; // 编译期常量拼接,等价于 "Object" System.out.println(str1 == str2); // true → 同一常量池对象 System.out.println(str1 == "Object"); // true → 字面量也指向常量池 System.out.println(str1 == str6); // true → "Obj"+"ect" 在编译期被优化为常量 "Object"
str6 的拼接发生在编译期(因 "Obj" 和 "ect" 均为编译时常量),JVM 将其视为等效字面量,同样存入常量池,故与 str1 共享引用。
❌ 运行时创建:绕过常量池的三种典型场景
以下情况均会在堆内存中新建对象,不自动进入常量池(除非显式调用 intern()),因此 == 比较结果为 false:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- new String("..."):强制在堆中创建新对象
- substring()(Java 7u6 之后):返回新分配的字符串对象(不再共享原字符串的底层 char[])
- 动态拼接(含变量):如 "Obj" + someVar,运行时计算,无法编译期优化
验证代码(添加 identityHashCode 辅助观察内存地址):
String name = "Object Oriented";
String str1 = "Object";
String str3 = new String("Object"); // 堆中新建对象
String str4 = name.substring(0, 6); // 运行时生成新字符串
String str5 = name.substring(0, 6); // 另一次调用,再建新对象
System.out.println(str1 == str3); // false → 不同地址
System.out.println(str1 == str4); // false → str4 在堆中,str1 在常量池
System.out.println(str4 == str5); // false → 两次 substring 返回两个独立对象输出示例(identityHashCode 近似反映内存地址):
Object==Object | 225991731==225991731: true // str1 与字面量同址 Object==Object | 225991731==342597804: false // str3 地址不同 Object==Object | 225991731==1308244637: false // str4 地址不同 Object==Object | 1308244637==1860944798: false // str4 ≠ str5
⚠️ 关键注意事项与最佳实践
- 永远不要用 == 比较字符串内容:即使某些情况下返回 true(如常量池复用),也属偶然行为,不可依赖。
- equals() 是内容比较的唯一可靠方式:它先判空,再逐字符比较,安全且语义明确。
- intern() 可手动归入常量池:str3.intern() == str1 将返回 true,但需权衡性能开销。
- IDE 警告有依据:主流 IDE(IntelliJ/Eclipse)会对 string == string 发出警告,正是基于此风险。
✅ 正确写法:if (str1.equals(str2)) { ... }
❌ 危险写法:if (str1 == str2) { ... }(逻辑脆弱,易引发隐蔽 Bug)
理解 == 的本质,不是为了“绕过” equals(),而是为了写出更健壮、可预测的 Java 代码——让引用语义清晰,让内容比较归于 equals(),各司其职,方为正道。

















