覆写equals方法必须覆写hashCode方法

简介:

覆写equals方法必须覆写hashCode方法,这条规则基本上每个Javaer都知道,这也是JDK API上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢?本建议就来解释该问题,我们先来看如下代码:

复制代码
 1 public static void main(String[] args) {  
 2      // Person类的实例作为Map的key  
 3      Map<Person, Object> map = new HashMap<Person, Object>() {  
 4         {  
 5             put(new Person("张三"), new Object());  
 6         }  
 7      };  
 8      // Person类的实例作为List的元素  
 9      List<Person> list = new ArrayList<Person>() {  
10         {  
11             add(new Person("张三"));  
12         }  
13      };  
14      // 列表中是否包含  
15      boolean b1 = list.contains(new Person("张三"));  
16      // Map中是否包含  
17      boolean b2 = map.containsKey(new Person("张三"));  
18 } 
复制代码

代码中的Person类与上一建议相同(http://www.cnblogs.com/DreamDrive/p/5431603.html),euqals方法完美无缺。在这段代码中,我们在声明时直接调用方法赋值,这其实也是一个内部匿名类的操作(下一个建议会详细说明)。现在的问题是b1和b2这两个boolean值是否都为true?

我们先来看b1,Person类的equals覆写了,不再判断两个地址是否相等,而是根据人员的姓名来判断两个对象是否相等,所以不管我们的new Person(“张三”)产生了多少个对象,它们都是相等的。把“张三”对象放入List中,再检查List中是否包含,那结果肯定是true了。

接着来看b2,我们把张三这个对象作为了Map的键(Key),放进去的对象是张三,检查的对象还是张三,那应该和List的结果相同了,但是很遗憾,结果是false。原因何在呢?

原因就是HashMap的底层处理机制是以数组的方式保存Map条目(Map Entry)的,这其中的关键是这个数组下标的处理机制:依据传入元素hashCode方法的返回值决定其数组的下标,如果该数组位置上已经有了Map条目,且与传入的键值相等则不处理,若不相等则覆盖;如果数组位置没有条目,则插入,并加入到Map条目的链表中。同理,检查键是否存在也是根据哈希码确定位置,然后遍历查找键值的。

接着深入探讨,那对象元素的hashCode方法返回的是什么值呢?它是一个对象的哈希码,是由Object类的本地方法生成的,确保每个对象有一个哈希码(这也是哈希算法的基本要求:任意输入k,通过一定算法f(k),将其转换为非可逆的输出,对于两个输入k1和k2,要求若k1=k2,则必须f(k1)=f(k2),但也允许k1≠k2,f(k1)=f(k2)的情况存在)。

那回到我们的例子上,由于我们没有重写hashCode方法,两个张三对象的hashCode方法返回值(也就是哈希码)肯定是不相同的了,在HashMap的数组中也就找不到对应的Map条目了,于是就返回了false。

问题清楚了,修改也非常简单,重写一下hashCode方法即可,代码如下:

复制代码
class Person {  
    /*其他代码相同,不再赘述*/  
    @Override  
    public int hashCode() {  
        return new HashCodeBuilder().append(name).toHashCode();  
    }  
} 
复制代码

其中HashCodeBuilder是org.apache.commons.lang.builder包下的一个哈希码生成工具,使用起来非常方便,诸位可以直接在项目中集成。(为什么不直接写hashCode方法?因为哈希码的生成有很多种算法,自己写麻烦,事儿又多,所以采用拿来主义是最好的方法。)

 


本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/5431725.html,如需转载请自行联系原作者

相关文章
|
4天前
|
存储 算法 Java
为什么要重写 hashcode 和 equals 方法
为什么要重写 hashcode 和 equals 方法
24 0
|
5月前
|
存储
重写equals后为什么要重写hashcode方法
重写equals后为什么要重写hashcode方法
46 0
|
4天前
|
自然语言处理 算法 Java
为什么说重写equals时要重写hashcode
为什么说重写equals时要重写hashcode
|
4天前
|
存储 Java
为什么要重写hashCode()和equals()(深入了解)
为什么要重写hashCode()和equals()(深入了解)
|
4天前
|
存储 IDE Java
为什么重写 equals() 时必须重写 hashCode() 方法?(简单易理解)
为什么重写 equals() 时必须重写 hashCode() 方法?(简单易理解)
21 1
|
9月前
|
存储
为什么重写 equals 方法就必须重写 hashCode 方法?
为什么重写 equals 方法就必须重写 hashCode 方法?
60 0
|
10月前
|
存储 Java
重写equals方法
我们在java程序中调用自带的equals方法时,你是否会有这样的疑问:明明我比较的数据都一样啊,为什么会返回false呢?有些人可能还会疑问,怎么有时候返回true?有时候返回false呢?这是为什么呢?其实是和Java底层人家写的equals方法逻辑有关系
|
10月前
为什么要重写 hashcode 和 equals 方法?
为什么要重写 hashcode 和 equals 方法?
57 0
|
存储 算法 Java
(强制)要求覆写equals必须覆写hashCode(原理分析)
hashCode和equals hashCode和equals用来标识对象,两个方法协同工作可用来判断两个对象是否相等。众所周知,根据生成的哈希将数据散列开来,可以使存取元素更快。对象通过调用Object.hashCode()生成哈希值;由于不可避免会存在哈希值冲突 的情况,因此当hashCode相同时,还需要再调用equals进行一次值的比较;但是若hashCode不同,将直接判定Object不同,跳过equals,这加快了冲突处理效率。Object类定义中对hashCode和equals要求如下:
197 0
|
Oracle Java 关系型数据库
为什么重写 equals() 方法,一定要重写 hashCode() 呢?| HashMap
首先我们有一个假设:任何两个 object 的 hashCode 都是不同的。 那么在这个条件下,有两个 object 是相等的,那如果不重写 hashCode(),算出来的哈希值都不一样,就会去到不同的 buckets 了,就迷失在茫茫人海中了,再也无法相认,就和 equals() 条件矛盾了,证毕。
121 0
为什么重写 equals() 方法,一定要重写 hashCode() 呢?| HashMap