福州网站建设公司中小企业,成都响应网站建设,关于公司建网站,旅游网站排行榜前20背景#xff1a;项目中遇到需要去重的类实体#xff0c;使用集合HashSet#xff0c;需要在该类中重写hashCode与equal方法#xff0c;了解一下Object中的这两个方法。
在 Java 中#xff0c;hashCode() 和 equals() 方法通常需要一起重写#xff0c;特别是当你创建自定义…背景项目中遇到需要去重的类实体使用集合HashSet需要在该类中重写hashCode与equal方法了解一下Object中的这两个方法。
在 Java 中hashCode() 和 equals() 方法通常需要一起重写特别是当你创建自定义类并希望该类的对象能够在基于哈希的集合如 HashMap、HashSet、LinkedHashMap、LinkedHashSet中正确工作时。
1. 为什么需要重写这两个方法
equals()默认实现Object.equals()比较的是对象的引用内存地址而大多数情况下我们希望比较对象的内容是否相等。hashCode()哈希集合如 HashMap依赖 hashCode() 来确定对象在哈希表中的存储位置。如果两个对象通过 equals() 比较相等但 hashCode() 返回不同的值会导致哈希集合无法正常工作例如无法正确存储或查找元素。
2. 何时需要重写
2.1 当你需要自定义对象的相等性逻辑时
示例场景 比较两个 Person 对象是否相等只要它们的 id 相同即认为相等。比较两个 Point 对象表示坐标点是否相等只要 x 和 y 坐标相同即认为相等。
2.2 当你的类会作为哈希集合的键时
必须同时重写 equals() 和 hashCode()确保 一致性如果两个对象 equals() 相等则它们的 hashCode() 必须相同。稳定性对象的 hashCode() 在其生命周期内不应改变通常基于不可变字段计算。
3. 如何正确重写
3.1 重写 equals() 的原则
自反性x.equals(x) 必须为 true。对称性x.equals(y) 为 true ⇒ y.equals(x) 也为 true。传递性若 x.equals(y) 和 y.equals(z) 为 true则 x.equals(z) 也为 true。一致性多次调用 x.equals(y) 结果应相同前提是对象未改变。非空性x.equals(null) 必须为 false。
例如
Override
public boolean equals(Object o) {if (this o) return true;if (o null || getClass() ! o.getClass()) return false;Person person (Person) o;return id person.id; // 假设通过id判断相等性
}
3.2 重写 hashCode() 的原则
相等性约束若 x.equals(y) 为 true则 x.hashCode() y.hashCode() 必须成立。散列均匀性尽量让不同的对象返回不同的哈希值减少哈希冲突。
例如
Override
public int hashCode() {int result 17; // 一个非零的初始值result 31 * result (field1 ! null ? field1.hashCode() : 0);result 31 * result (field2 ! null ? field2.hashCode() : 0);return result;
}
4. 常见误区与注意事项 只重写 equals() 而不重写 hashCode() 会导致哈希集合如 HashMap、HashSet无法正常工作。例如 Person p1 new Person(1, Alice);
Person p2 new Person(1, Alice);
SetPerson set new HashSet();
set.add(p1);
set.contains(p2); // 返回false即使p1和p2通过equals()相等 使用 IDE 自动生成方法 大多数 IDE如 IntelliJ、Eclipse可以自动生成 equals() 和 hashCode()基于对象的字段计算。 不可变类如 String、Integer 这些类已经正确重写了 equals() 和 hashCode()因此可以直接用作哈希集合的键。
总结
必须重写当你的类需要自定义相等性逻辑或作为哈希集合的键时。成对重写重写 equals() 时必须同时重写 hashCode()确保两者一致性。使用工具利用 IDE 或 Lombok 等工具自动生成方法减少手动错误。
扩展知识
hashCode方法重写时使用31作为乘数的原因主要包括以下几点 奇质数的特性31是一个奇质数这意味着它能有效地减少哈希冲突的概率。使用质数作为乘数可以帮助分散哈希值从而提高哈希表的性能12。 位运算效率在计算机中乘以31可以通过位运算来优化具体为(x 5) - x。这种方式比直接乘法更加高效因为位移操作通常比乘法快得多12。 良好的分布性经过实践证明31可以提供良好的哈希值分布适用于字符串等对象的哈希计算。它能够有效地将不同的输入映射到不同的哈希值上减少了碰撞的可能性12。 历史原因和测试结果31作为一个不大不小的质数经过大量测试表明其在哈希计算中表现良好冲突率较低。例如使用31、33、37、39和41作为乘数进行哈希计算时31的冲突结果最少4。