equals()
和hashCode()
在 Object 类中定义
- hashCode():用于计算对象哈希值。
- equals():用于比较对象是否相等。
默认实现
Object
定义的方法
默认实现:均基于对象引用地址。
-
equals():比较对象引用地址。
-
hashCode():返回对象引用地址(本地方法)。
public boolean equals(Object obj) { return (this == obj); } public native int hashCode();
方法重写
① 原因
为什么要重写?
- 哈希集合的检索机制中,使用了
hashCode()
和equals()
。 - 在默认实现下,只有同一个对象引用的
equals()
和hashCode()
才会相等。 - 在实际业务中,通常认为两个对象属性相同则对象相等。
- 需要成对重写
hashCode()
和equals()
,才能实现对象的区分性。
示例
HashMap<User> userMap = new HashMap<>;
User u1 = new User("secret", 20);
User u2 = new User("secret", 20);
userMap.put(u1, "user1");
userMap.get(u2); // 能获取到吗?
- 未重写的情况:不能。因为 u1 和 u2 是不同的对象引用,
hashcode()
和equals()
比较不相等。 - 重写的情况:能。因为自定义了
hashCode()
计算规则、equals()
比较条件,u1 和 u2 视为相等的对象。
② 重写 equals()
通常认为:对象的属性值完全相同,则对象相等。
-
参数检查:
- 相同引用
- 判空
- 判类型:
getClass()
(严格):返回运行时具体类型,不考虑继承关系。instanceOf
(宽松):测试对象是否为类的实例(或接口实现类)。
-
比较属性:先向下转型,再比较属性值。
-
基本类型:使用
==
。 -
引用类型:使用
Objects.equals()
方法,避免NPE
。@Override public boolean equals(Object obj) { if (this == obj) { return true; } // 若严格要求类型一致,条件二改成 this.getClass() != obj.getClass() if (obj == null || !obj instanceof Person) { return false; } Person p = (Person) obj; // 不使用 xxx.equals(xxx),避免NPE return Objects.equals(this.name, p.name) && this.age == p.age; }
-
③ 重写 hashCode()
原则:尽量避免哈希冲突。
此处使用
Objects
工具类的方法。
@Override
public int hashCode() {
return Objects.hash(name, age);
}
分析:
Objects
的hash(...)
-
Objects.hash(...):
-
可变参数(数组)
-
调用
Arrays.hashCode(...)
计算哈希值。public static int hash(Object... values) { return Arrays.hashCode(values); }
-
-
Arrays.hashCode(...):哈希算法
hash = 31 * hash + hash(i)
-
基于多个属性计算。
-
基于迭代的方式计算。
public static int hashCode(Object a[]) { if (a == null) return 0; int result = 1; for (Object element : a) result = 31 * result + (element == null ? 0 : element.hashCode()); return result; }
-
思考
选用
31
作为乘子的好处
- 质数:在计算时可以尽量减少哈希冲突。
- 性能优化:
- 代码运行频繁时,JVM 会将
31 * i
优化为位运算(i<<5) - 1
。 - 位运算的执行效率高。
- 代码运行频繁时,JVM 会将
方法成对重写后,
equals()
和hashCode()
的关系
结论:
-
equals()
和hashCode()
都相等,才认为对象相同。 -
若
equals()
相等,则hashCode()
相等。描述 成立? 逆命题 若 hashCode()
相等,则equals()
相等❌(哈希冲突) 否命题 若 equals()
不相等,则hashCode()
不相等❌(哈希冲突) 逆否命题 若 hashCode
不相等,则equals()
不相等✔