== 比较引用是否指向同一内存地址,equals() 比较内容是否逻辑相等;字符串字面量因常量池可能使 == 为 true,但应始终用 equals() 判断内容;自定义类需重写 equals() 和 hashCode() 才能按业务逻辑比较。

区分 == 和 equals() 的关键,不在于“哪个更好”,而在于“它们本来就在做不同的事”:一个看是不是同一个东西(地址),一个看内容是不是一样(逻辑相等)。
字符串比较:常量池让 == 有时“碰巧”为 true
String 是最典型的例子,但容易让人误解。根本原因在于 Java 的字符串常量池机制:
-
==比较的是两个引用是否指向堆中同一块内存地址。比如new String("hello") == new String("hello")一定是false,因为每次new都新建对象,地址不同。 -
equals()在 String 类中已被重写,逐字符比内容。所以上面那行的equals()返回true。 - 但像
String s1 = "hello"; String s2 = "hello";这种字面量赋值,JVM 会把它们放进常量池并复用同一对象,此时s1 == s2也返回true——这不是 equals 生效了,而是地址真相同了。 - 别依赖这种“碰巧”。生产代码中判断字符串内容是否一致,一律用
equals();用==只适合极少数场景,比如确认是否是某个特定的空字符串常量或单例标识。
自定义对象比较:默认 equals() 和 == 完全等价
如果你写了一个类,比如 Person,没动过 equals() 方法,那么它的行为就和 Object 类里的一模一样:
-
public boolean equals(Object obj) { return (this == obj); }—— 看,底层就是==。 - 所以
new Person("张三", 25).equals(new Person("张三", 25))一定返回false,哪怕所有字段都一样,因为是两个不同对象。 - 要让它按业务规则比较(比如姓名+年龄相同就算相等),必须手动重写
equals(),且必须同时重写hashCode(),否则放进HashMap或HashSet会出现存进去却找不到的问题。
什么时候该用 ==,什么时候该用 equals()?
看目的,不看类型:
- 想确认两个变量是不是指向同一个实例(比如检查回调是否重复注册、校验单例对象、判断状态机当前是否处于某个固定实例状态),用
==。 - 想确认两个对象在业务意义上是否“相等”(比如两个订单金额和商品清单一样、两个用户身份证号相同),必须用重写后的
equals()。 - 基本类型(
int、char等)只能用==,没有equals()方法;包装类(Integer、Character)建议统一用.equals(),避免因缓存(如 -128~127)导致行为不一致。 - 为防空指针,推荐用
Objects.equals(a, b),它内部自动处理了null安全问题。

















