Java中基于equals()比较含同对象不同实例的两个Set是否相等
equals()判定相等的问题 这个问题我之前踩过坑!核心原因是你只重写了Coordinate类的equals()方法,却没有重写hashCode()——这违反了Java中equals()和hashCode()的强制约定,直接导致集合的比较逻辑失效了。
为什么会出现这个问题?
Java里的Set(比如常用的HashSet)在处理元素时,会先通过hashCode()来定位元素的存储位置,只有当两个元素的hashCode相等时,才会调用equals()做进一步的相等性判断。你的两个Coordinate(2,2)实例虽然equals()返回true,但默认的hashCode()是基于对象内存地址生成的,所以它们的hashCode值完全不同。在Set眼里,这就是两个完全不同的元素,自然A.equals(B)会返回false。
最规范的解决方案:重写hashCode()
给Coordinate类补充hashCode()方法,确保所有参与equals()判断的字段(这里是x和y)都参与hashCode的计算,和equals()逻辑保持一致。代码示例:
import java.util.Objects; public class Coordinate { public int x; public int y; public Coordinate(int x, int y) { this.x = x; this.y = y; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; Coordinate coordinate = (Coordinate) obj; return coordinate.x == this.x && coordinate.y == this.y; } // 新增hashCode方法 @Override public int hashCode() { return Objects.hash(x, y); } }
我还给你的
equals()补了几个健壮性判断:先判断是否是同一对象,再判断类型,避免ClassCastException,这样代码更安全。
重写完hashCode()之后,直接调用A.equals(B)就能得到正确结果了——因为现在Set会正确识别出两个Coordinate(2,2)实例是相等的元素,当两个集合的元素完全一致时,集合就会被判定为相等。
特殊场景:无法修改Coordinate类的解决办法
如果因为权限或其他原因不能修改Coordinate类,你可以手动实现一个集合比较的工具方法,通过遍历+元素存在性检查来判断:
public static boolean compareCoordinateSets(Set<Coordinate> setA, Set<Coordinate> setB) { // 先判断大小,大小不同直接返回false if (setA.size() != setB.size()) { return false; } // 遍历setA的每个元素,检查是否都在setB中存在 for (Coordinate coord : setA) { if (!setB.contains(coord)) { return false; } } return true; }
这个方法的逻辑很直白:只要两个集合大小相同,且A中的每个元素都能在B中找到(通过equals()判断),就认为两个集合相等。不过这种方式的效率比直接用Set的equals()低,适合临时应急。
补充:Java的equals()和hashCode()约定
Java官方文档明确要求:
- 如果两个对象通过
equals()返回true,那么它们的hashCode()必须返回相同的值; - 如果两个对象的
hashCode()返回不同的值,那么equals()必须返回false。
遵守这个约定是保证所有基于哈希的集合(HashSet、HashMap等)正常工作的前提,以后写自定义类时一定要记得同时重写这两个方法哦!
内容的提问来源于stack exchange,提问作者11thHeaven

