结论
1.equal()相等的两个对象他们的hashCode()肯定相等,也就是用equal()对比是绝对可靠的。
2.hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。
3.重写equals方法,必须重写hashcode方法(因为equals返回true,两个对象的hashcode必须相同);
4.重写hashcode方法,不必重写equals方法。(相当于替换hash算法)
验证
1.针对第3个结论,使用反证法:重写equals,不重写hashcode方法,看看会有什么问题:
public class ObjectTest {
static class Person {
private String name;
private Integer age;
Person(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj != null && obj instanceof Person) {
Person pobj = (Person) obj;
if (!Objects.equals(name, pobj.name)) return false;
return Objects.equals(age, pobj.age);
}
return false;
}
}
public static void main(String[] args) {
Person p1 = new Person("aaa", 12);
Person p2 = new Person("aaa", 12);
//此处打印:true
System.out.println(p1.equals(p2));
Map<Person, String> map = new HashMap<>();
map.put(p1, "student");
//此处打印:null
System.out.println(map.get(p2));
}
}
代码分析:
针对p1和p2两个Person对象,第一个打印语句显示,p1.equals(p2);
第二段代码实例化一个hashmap,Person类作为key值,value是字符串类型,此时向map中添加一个entry,key为p1,value为"student",从上一段代码得知,p1.equals(p2),那么以p2作为key理论上应该也可以获得"student"字符串,然而打印结果是null,这表明,p1和p2的hashcode不相等,从而得出结果:equals方法返回true,hashcode却不相等,这与实际是不相符的,所以此时hashCode方法不再满足需要,需要重写。如下(一种写法,非唯一写法):
@Override
public int hashCode() {
int nameHash = name.hashCode();
return 31 * nameHash + age;
}
2.针对第4个结论,Object类的equals方法比较的是对象的内存地址,因此,equals相等的对象是同一个内存对象,其hashcode不管使用何种hash算法都是一样的。