zoukankan      html  css  js  c++  java
  • [改善Java代码]覆写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方法?因为哈希码的生成有很多种算法,自己写麻烦,事儿又多,所以采用拿来主义是最好的方法。)

  • 相关阅读:
    Android sensor 系统框架 (一)
    enc28j60网卡驱动模块添加进linux内核,Kconfig,Makefile配置过程
    Linux samba服务器配置
    为群晖加把锁:使用ssh密钥保障数据安全
    浦发银行网上银行U盾证书无法更新的解决办法
    克隆Linux系统的网卡设置
    Linux路由:CentOS6的多种玩法
    专心学LINUX:CentOS关闭屏幕自动锁定和睡眠
    群晖:关闭软路由利用双网卡桥接直连电脑上网
    Ceph之二----部署Ceph集群
  • 原文地址:https://www.cnblogs.com/DreamDrive/p/5431725.html
Copyright © 2011-2022 走看看