==比较基本类型值、引用类型地址(字符串字面量例外);equals默认同==,重写后比内容;自定义类须重写equals与hashCode;推荐用Objects.equals()安全判空。

== 比较的是地址还是值,取决于类型
对 int、char、boolean 这类基本类型,== 直接比数值——int a = 5; int b = 5; a == b 就是 true。
但对 String、ArrayList、自定义类这类引用类型,== 比的是内存地址——哪怕两个 new String("abc") 内容一模一样,== 也返回 false,因为它们是堆里两个独立对象。
- 字符串字面量例外:
String s1 = "abc"; String s2 = "abc"; s1 == s2是true,因为都指向字符串常量池中同一个实例 -
new String("abc")总是新建堆对象,不会进常量池(除非显式调用intern()) - 拿
==判断两个引用类型是否“逻辑相等”,99% 的情况是错的
equals() 默认行为和 String 等类的实际行为完全不同
equals() 是 Object 类的方法,它的原始实现就一行:return (this == obj);——跟 == 完全一样。
但像 String、Integer、LocalDateTime 这些类都重写了它,变成比内容:
立即学习“Java免费学习笔记(深入)”;
-
"abc".equals(new String("abc"))→true(先判空、再判类型、再逐字符比) -
new Integer(123).equals(new Integer(123))→true(比的是int值) - 你写的
Person p1 = new Person("Alice", 30); Person p2 = new Person("Alice", 30);,如果不重写equals(),p1.equals(p2)就是false
自定义类必须重写 equals() 才能按需比较
如果你希望两个 Person 对象在姓名和年龄相同时算“相等”,就必须手动重写 equals() 方法:
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return age == person.age && Objects.equals(name, person.name);
}
- 开头的
this == obj是性能优化,避免后续冗余判断 - 必须检查
obj == null,否则传入null会抛NullPointerException - 务必同时重写
hashCode(),否则放进HashSet或作HashMap键时行为异常 - 别用
instanceof判子类(如Employee extends Person),会导致不对称问题;用getClass() != obj.getClass()更安全
日常开发中最该用 Objects.equals() 而不是手写判空
直接调 a.equals(b) 很危险:如果 a 是 null,立刻 NullPointerException;写成 b != null && b.equals(a) 又啰嗦还可能漏掉 a 为 null 的情况。
标准解法是用 JDK 7+ 提供的 Objects.equals(a, b):
- 内部自动处理了
null:两边都null→true;一null一非null→false;都不null→ 调a.equals(b) - 所有场景优先用它,包括
Map.get(Objects.equals(key, targetKey))这类逻辑 - 别自己封装类似工具方法——
Objects已经稳定、高效、被广泛验证
最易忽略的一点:重写 equals() 时若用到字段,这些字段本身也要保证能正确比较(比如字段是另一个自定义对象,它也得重写 equals() 和 hashCode())。










