== 比较内存地址,equals() 比较字符内容;字面量字符串常驻常量池故 == 可能为 true,new 创建则地址不同;equals() 无视创建方式,内容相同即返回 true。

String 类中,== 和 equals() 的行为差异,本质是“地址比较”与“内容比较”的区别,但具体表现受字符串创建方式影响很大。
双等号(==)比的是内存地址,不是内容
对 String 变量使用 ==,判断的是两个引用是否指向**同一块内存地址**:
- 字面量直接赋值(如
String s1 = "abc"; String s2 = "abc";)→ 通常指向字符串常量池中同一个对象 →s1 == s2为true - 用
new String("abc")创建 → 总是在堆中新建对象 → 即使内容相同,地址也不同 →==为false - 拼接或运行时生成的字符串(如
"ab" + "c"、sb.toString())→ 是否进常量池要看编译期能否确定,不确定则不共享地址
equals() 比的是字符序列是否一致
String.equals() 是重写后的方法,它逐个比较两个字符串的字符内容(长度 + 每个 char 值),只要内容完全相同就返回 true:
- 无论字符串来自常量池、堆、StringBuilder 转换,还是不同变量名,只要字符序列一样,
equals()就为true - 该方法内部做了 null 安全检查(JDK 7+),调用
s1.equals(s2)时若s1为 null 会抛NullPointerException;更稳妥可用Objects.equals(s1, s2) - 注意:不是所有类都重写了
equals(),比如StringBuffer没重写,它的equals()仍等价于==
为什么 String 要这样设计?
这是 Java 对不可变性与性能的权衡:
- 字符串常量池复用相同字面量,节省内存,
==快速判断是否为同一对象 - 但业务逻辑几乎总是关心“内容是否一样”,所以
String重写了equals(),让它语义更自然 - 开发者必须清楚:想确认是否是“同一个字符串实例”,用
==;想确认“看起来是不是一样的文字”,必须用equals()
常见误用和建议
- 绝不用
==判断用户输入、配置项、数据库字段等字符串内容是否相等 - 避免
str.equals("xxx")这种写法——若str可能为 null,应改用"xxx".equals(str)或Objects.equals(str, "xxx") - 调试时可配合
System.identityHashCode(obj)看地址哈希,辅助验证==结果 - 需要严格区分“同对象”和“同内容”场景(如缓存 key、对象唯一标识),才需同时关注两者









