分享知识 传递快乐
equals方法和hashCode方法都是Object类中的方法。
equals方法在其内部是调用了"==",所以说在不重写equals方法的情况下,equals方法是比较两个对象是否具有相同的引用,即是否指向了同一个内存地址。而hashCode是一个本地方法,他返回的是这个对象的内存地址。
hashCode通用规定
- 在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对同一个对象的多次调用,hashCode方法都必须始终返回同一个值。在一个应用程序与另一个应用程序的执行过程中,执行hashCode方法所返回的值可以不一致。
- 如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中的hashCode方法都必须产生同样的整数结果
- 如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中的hashCode方法,则不一定要求hashCode方法必须产生不用的结果。但是程序员应该知道,给不相等的对象产生截然不同的整数结果,有可能提高散列表的性能。
由此可知,如果重写了equals方法而没有重写hashCode方法的话,就违反了第二条规则。相等的对象必须拥有相等的hashcode。
不重写hashCode方法所带来的严重后果
public class User {
private Long id;
private String name;
public User(Long id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public boolean equals(final Object o) {
if (this == o)
return true;
if (!(o instanceof User))
return false;
if (super.equals(o))
return true;
final User user = (User) o;
if (id != null ? !id.equals(user.id) : user.id != null)
return false;
return name != null ? name.equals(user.name) : user.name == null;
}
public static void main(String[] args) {
User u1 = new User(1L, "root");
User u2 = new User(1L, "root");
Map<User, Integer> hashMap = new HashMap<>();
hashMap.put(u1, 1);
System.out.println(u1.equals(u2));
System.out.println(hashMap.containsKey(u2));
}
}
输出结果
true
false
对于第一个输出true我们很容易知道,因为我们重写了equals方法,只要两个对象的name属性相同就会返回ture。但是为什么第二个为什么输出的是false呢?就是因为我们没有重写hashCode方法。所以我们得到一个结论:如果一个类重写了equals方法但是没有重写hashCode方法,那么该类无法结合所有基于散列的集合(HashMap,HashSet)一起正常运作。
重写hashCode方法
@Override
public int hashCode() {
int result = 1;
result = 31 * result + (id != null ? id.hashCode() : 0);
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
输出结果
true
true
然而重写了equals,且u1.equals(u2)返回true,根据hashcode的规则,两个对象相等其哈希值一定相等,所以矛盾就产生了,因此重写equals一定要重写hashcode,而且从类重写后的hashcode方法中可以看出,重写后返回的新的哈希值与User的两个属性有关。
总结:
- 两个对象相等,hashcode一定相等
- 两个对象不等,hashcode不一定不等
- hashcode相等,两个对象不一定相等
- hashcode不等,两个对象一定不等
————————————
如有不妥之处请留言指正。
相互学习,共同进步。