- 在任何一个类中,如果需要重写
equals
方法,一定要重写hashCode
方法。否则在使用HashMap
或HashSet
集合类的时候,就会出现问题。
哈希表中如何比较两个对象是否相同?
- 已知:
- 当两个对象
equals
方法返回true
时,则两个对象就是相同的。 - 哈希表中不能存储两个相同的元素
- 当两个对象
- 那么我们将对象放入哈希表时,哈希表是如何做出判断的呢?
- 先比较两个对象的哈希值,如果哈希值不同,则两个对象一定不同,此时不会调用
equals
方法进行比较。 - 如果两个对象的哈希值相同,则调用
equals
方法进行比较,来判断两个对象是否相同。
- 先比较两个对象的哈希值,如果哈希值不同,则两个对象一定不同,此时不会调用
- 因此:
- 如果两个对象通过
equals
方法比较是相等的,那么它们的hashcode
方法结果值也必须是相等的。 - 如果你更改了
equals
方法的比较标准,那么hashCode
方法也要随之改变。
- 如果两个对象通过
为什么重写 equals 方法就必须重写 hashCode 方法?
- 如果重写了
equals
方法,而没有重写hashCode
方法,就有可能导致equals
返回true
,而hashCode
返回的哈希值不相同。 - 那么哈希表在存储数据的时候,比较到两个对象的哈希值不相同,就会认为两个对象不相同,不会再调用
equals
方法,而直接将两个对象都存储在哈希表中,这就导致了哈希表的错误。
代码测试
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj == null || getClass() != obj.getClass()) {
return false;
} else {
Point point = (Point) obj;
return x == point.x && y == point.y;
}
}
}
- 创建一个
Point
类,有两个成员变量x
和y
,并重写了equals
方法,但没有重写hashCode
方法,然后进行测试。
import java.util.HashSet;
import java.util.Set;
public class Test {
public static void main(String[] args) {
Point point1 = new Point(3, 4);
Point point2 = new Point(3, 4);
Point point3 = new Point(0, 0);
System.out.println(point1.equals(point2));
System.out.println(point1.equals(point3));
Set<Point> set = new HashSet<>();
set.add(point1);
set.add(point2);
set.add(point3);
System.out.println(set);
}
}
-
可以看到第一次比较结果为
true
,第二次为false
,符合我们的需求,但是当我们将三个对象放入 HashSet 中的时候,发现虽然point1
和point2
是相同的,但还是分别都进入了set
集合中。 -
现在我们重写
hashCode
方法,并重新进行测试:
import java.util.Objects;
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj == null || getClass() != obj.getClass()) {
return false;
} else {
Point point = (Point) obj;
return x == point.x && y == point.y;
}
}
@Override
//Objects类的一个静态方法,它接受任意数量的对象并为它们返回一个哈希码
public int hashCode() {
return Objects.hash(x, y);
}
}
- 可以看到只有不同的两个对象进入了集合中,符合了我们的要求。