为什么要同时重写hashcode和equals?

首先看看jdk中objec的hashCode方法的定义:
1.相同的对象,返回的hash code一定是一样的
2.如果两个对象调了equals返回true,则两个对象的hash code是一样的
3.如果两个对象调了equals返回false,则两个对象的hashcode不一样,这种特性会提高hash table的效率
再看equals方法的定义:
假如equals被重写,则hashcode也需要被重写,来维护一个特性:当两个对象调equals返回true,则两个对象的hashcode是一致的

那总结一下,其实在jdk的文档中,并没有硬性要求一定要同时修改这两个方法,只是要求,当equals方法被重写,hashcode也必须要被重写。
目的:要维持对象的一个规则,当两个对象调equals返回true,则两个对象的hashcode是一致的

然后为什么要维持这个特性?因为jdk基于这个特性,实现了HashMap或HashSet等类,key在使用之前都经过hashcode,所以,假如一个类只重写equals方法,创建了两个对象字段一致(equals返回true),而hashcode没有重写,默认根据内存地址来计算,所以两者不一致。
而HashMap或者HashSet里面判断元素相等会用hash值来做判断,这就和equals方法返回的结果不一致,也就造成了逻辑上的错误。其中一个例子就是:使用key的时候是会先对key做hash,然后再做处理,那两个equal的对象作为key,可能会得到不一致的效果。

最后再说一句,那我只实现hashcode行不?其实也可以~(至少我目前看来是这样,假如认知错误,欢迎指正)
最最后再说一句,还记得上面说的“如果两个对象调了equals返回false,则两个对象的hashcode不一样,这种特性会提高hash table的效率”吗?
可以看下HashTable的源码:

public synchronized boolean containsKey(Object key) {
    Entry<?,?> tab[] = table;
    int hash = key.hashCode();
    int index = (hash & 0x7FFFFFFF) % tab.length;
    for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
        if ((e.hash == hash) && e.key.equals(key)) {
            return true;
        }
    }
    return false;
}


可以看到判断有没有包含key,是会同时判断hash值和equals的返回结果的,假如两个不equal的对象,返回的hashcode不相等,其实if ((e.hash == hash) && e.key.equals(key)只会执行第一段而已,效率就提高了


版权声明:本文为u011548068原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。