一句话总结:
== 比地址,equals 比内容,hashCode 是身份证号——三个兄弟各司其职,协作才能不乱套!
一、== 运算符:认脸不认人
-
作用:比较两个变量的内存地址是否相同(是不是同一个对象)。
-
适用场景:
- 基本数据类型(
int,double等):直接比值。 - 对象类型(
String,自定义类):比地址(是否指向同一块内存)。
- 基本数据类型(
int a = 10;
int b = 10;
System.out.println(a == b); // true(值相等)
String s1 = new String("喵");
String s2 = new String("喵");
System.out.println(s1 == s2); // false(不同对象,地址不同)
二、equals() 方法:认内容不认脸
- 默认行为:和
==一样,比地址(Object类的默认实现)。 - 重写后:比对象内容是否相同(如
String、Integer等已重写)。 - 重点:自定义类必须手动重写
equals()才能比内容!
class Cat {
String name;
Cat(String name) { this.name = name; }
// 手动重写 equals()
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // 地址相同直接返回 true
if (obj == null || getClass() != obj.getClass()) return false;
Cat cat = (Cat) obj;
return Objects.equals(name, cat.name); // 比名字内容
}
}
Cat c1 = new Cat("咪咪");
Cat c2 = new Cat("咪咪");
System.out.println(c1.equals(c2)); // true(内容相同)
System.out.println(c1 == c2); // false(地址不同)
三、hashCode() 方法:身份证号
-
作用:返回对象的哈希码(整数),用于哈希表(如
HashMap,HashSet)快速查找。 -
核心规则:
- 如果两个对象
equals()为 true,它们的hashCode()必须相同(否则哈希表会错乱)。 hashCode()相同,equals()不一定为 true(哈希碰撞正常)。
- 如果两个对象
// 错误示例:重写 equals() 但没重写 hashCode()
class Dog {
String name;
@Override
public boolean equals(Object obj) { /* 比名字 */ }
// 没重写 hashCode() → 默认用 Object 的 hashCode()(不同对象值不同)
}
Dog d1 = new Dog("旺财");
Dog d2 = new Dog("旺财");
Set<Dog> set = new HashSet<>();
set.add(d1);
set.add(d2);
System.out.println(set.size()); // 输出 2!因为 hashCode 不同
正确做法:
@Override
public int hashCode() {
return Objects.hash(name); // 用 name 生成哈希码
}
// 此时 d1 和 d2 的 hashCode 相同,set.size() 为 1
四、三者关系总结
| 操作 | 比较内容 | 重写要求 | 常见用途 |
|---|---|---|---|
== | 内存地址 | 不能重写 | 基本类型比较、对象地址判断 |
equals() | 对象内容 | 需手动重写 | 自定义对象内容比较 |
hashCode() | 哈希码(整数) | 必须和 equals() 一致 | 哈希表存储与查找 |
五、避坑指南
-
永远同时重写
equals()和hashCode():- 用 IDE 自动生成(如 IntelliJ 的
Generate→equals() and hashCode())。 - 或用
Objects.equals()和Objects.hash()简化代码。
- 用 IDE 自动生成(如 IntelliJ 的
-
处理
null安全:@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; // ... } -
小心可变字段参与哈希计算:
- 如果对象字段会变,可能导致存进哈希表后找不到(哈希码变了,但存储位置没变)。
总结口诀:
“基本类型用 ==,对象地址也比它。
内容相等用 equals,重写别忘 hashCode。
哈希一致是铁律,否则 Map 要崩盘!”