equals和hashcode是Object的方法。因此每个类都具有这两个方法。
这里直说当我们自定义对象后需要把对象放进集合中时,这两个方法如何工作。
import java.util.HashSet;
import java.util.Set;
public class test {
static class rel{
int x;
int y;
rel(int x, int y){
this.x = x;
this.y = y;
}
}
public static void main(String[] args) {
Set<rel> s = new HashSet<>();
rel r = new rel(2,3);
s.add(r);
System.out.println(s.contains(r));
s.add(new rel(1,2));
System.out.println(s.contains(new rel(1,2)));
}
}
Output:
true
false
通过第二个false可以看到,虽然对象的内容是一样的。但是set集合依然判断不存在。当然,如果添加的是对象的引用的话,那么属于同一个对象,就是可以的。
我们的目标是,如果对象内容相同,那么就属于重复对象。为此,先看一下set,hashmap这种集合判重的流程。
- 首先判断hashCode是否一样 如果不一样 就不存在 直接添加
- 如果hashCode一样 调用equals方法判断 如果equals返回true 说明重复 覆盖
- 如果equals返回false 那么说明不存在 添加
所以,我们只需要重写hashCode和equals方法即可。
import java.util.HashSet;
import java.util.Set;
public class test {
static class rel{
int x;
int y;
rel(int x, int y){
this.x = x;
this.y = y;
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return 1;
}
@Override
public boolean equals(Object obj) {
rel r = (rel) obj;
return (x == r.x && y == r.y);
}
}
public static void main(String[] args) {
Set<rel> s = new HashSet<>();
rel r = new rel(2,3);
s.add(r);
System.out.println(s.contains(r));
s.add(new rel(1,2));
System.out.println(s.contains(new rel(1,2)));
}
}
Output:
true
true
最后注意,重写的时候要满足 equals相同 则hashCode一定相同。
如果对Hash表有了解,就很容易理解上面这个原则,因为Hash函数虽然尽最大的努力去分离不同的值,但是肯定会发生冲突。
之所以先用hashCode就时因为Hash函数都设计的非常快,如果冲突了,再去用equals检查内容,这样效率更高。