热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

覆盖equals的时候总要覆盖hashCode

importjava.util.HashMap;publicclassStudent{privateStringname;privateSt
import java.util.HashMap;


public class Student {

    private String name ;
    
    private String id;
    
    public Student(String name , String id) {
        this.id = id;
        this.name = name;
    }
    
    public String getName() {
        return this.name;
    }
    
    public String getId() {
        return this.id;
    }
    
    @Override
    public boolean equals(Object o) {
        if(o==this)
            return true;
        if(!(o instanceof Student)) 
            return false;
        
        Student t = (Student)o;
        if(!name.equals(t.getName())) 
            return false;
        if(!id.equals(t.getId()))
            return false;
        return true;
    }
    
    public static void main(String[] args) {
        HashMap map = new HashMap();
        Student t1 = new Student("s1","1");
        Student t2 = new Student("s1","1");
        System.out.println(t1.equals(t2));
        map.put(t1, 1);
        map.put(t2, 1);
        System.out.println(map.size());
    }
    
}

运行结果
true
2

从上面运行 的结果就可以看到,虽然两个对象是“相等的”,但是map中却存放着两个值,这与map中key值唯一似乎的矛盾的,这个出现这个原因就是没有重写hashCode()方法,两个对象的散列码不一样,map在处理的时候就当做不同的对象来处理。---(因为hashcode不一样,那么认为equals方法也为false),如果如下所示,重写hashCode()方法,则只有一个值

@Override
    public int hashCode() {
        int result = 17;
        int c = 0;
        c = this.name.hashCode();
        result = 31 * result+c;
        c= this.id.hashCode();
        result = 31*result+c;
        return result;
    }

 

在Object规范中,有如下内容:

1) 只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法都必须始终如一的返回同一个整数。在一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。 
2)如果连个对象根绝equals方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。 

3)如果两个对象根据equals方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定产生不同的整数结果。

如果覆盖equals时没有覆盖hashCode方法,则违反了约定的第二条。

 

一个好的hashCode函数通常倾向于“为不相等的对象产生不相等的散列码”,这正是hashCode约定中第三条的意义。

一个比较好的生成hashCode函数的方法如下:

1、把某个非零常数值,比如说17,保存在一个叫result 的int 类型的变量值中。

2、对于对象中的每一个关键域f (指equals 方法中考虑的每一个域,非equals用到的域一概不要考虑),完成以下步骤:

  • a 为该域计算int 类型的散列码c:
    • i如果该域是boolean 类型,则计算(f ? 1 : 0);
    • ii如果该域是byte、char、short 或者int 类型,则计算(int)f;
    • iii如果该域是long 类型,则计算(int)(f ^ (f >>> 32));
    • iv如果该域是float 类型,则计算Float.floatToIntBits(f);
    • v如果该域是double 类型,则计算Double.doubleToLongBits(f) 得到一个long 类型的值,然后按照步骤2.a.iii 对该long 类型计算散列值;
    • vi如果该域是一个对象引用,并且该类的equals 方法通过递归调用equals 的方式来比较这个域,则同样对这个域递归调用hashCode 方法;如果要求一个更为复杂的比较,则为这个域计算一个“规范表示”,然后针对这个规范表示调用hashCode。如果这个域的值为null,则返回0;
    • vii如果该域是一个数组,则把每一个元素当做单独的域来处理。然后根据步骤2.b 中的做法把这些散列值组合起来。
  • b 按照下面的公式,把步骤a 中计算得到的散列码c 组合到result 中:
    result = 31 * result + c;

3、返回result 值。

注:根据实践经验,在对ASCII 串的散列函数中,31 和37 是很好的散列因子。

注意:必须排除equals方法没有用到的任何域。也不要试图从散列码中排除掉一个对象的关键部分来提高性能。

如果一个类是不可变的,并且计算散列值的代价也比较大,那么就没有必要每次都计算了,应该考虑把散列码缓存在对象内部。


推荐阅读
  • 设计一个算法,用于计算给定字符串中出现的不同ASCII字符数量。该任务将重点考察字符串处理、集合操作以及基础的输入输出技术。 ... [详细]
  • Hadoop MapReduce 实战案例:手机流量使用统计分析
    本文通过一个具体的Hadoop MapReduce案例,详细介绍了如何利用MapReduce框架来统计和分析手机用户的流量使用情况,包括上行和下行流量的计算以及总流量的汇总。 ... [详细]
  • Java连接MySQL数据库的方法及测试示例
    本文详细介绍了如何安装MySQL数据库,并通过Java编程语言实现与MySQL数据库的连接,包括环境搭建、数据库创建以及简单的查询操作。 ... [详细]
  • 本文探讨了如何通过Service Locator模式来简化和优化在B/S架构中的服务命名访问,特别是对于需要频繁访问的服务,如JNDI和XMLNS。该模式通过缓存机制减少了重复查找的成本,并提供了对多种服务的统一访问接口。 ... [详细]
  • 使用Java计算两个日期之间的月份数
    本文详细介绍了利用Java编程语言计算两个指定日期之间月份数的方法。文章通过实例代码讲解了如何使用Joda-Time库来简化日期处理过程,旨在为开发者提供一个高效且易于理解的解决方案。 ... [详细]
  • 本文探讨了如何使用Scrapy框架构建高效的数据采集系统,以及如何通过异步处理技术提升数据存储的效率。同时,文章还介绍了针对不同网站采用的不同采集策略。 ... [详细]
  • 编码unicode解决了语言不通的问题.但是.unicode又有一个新问题.由于unicode是万国码.把所有国家的文字都编进去了.这就导致一个unicode占用的空间会很大.原来 ... [详细]
  • 本文基于Java官方文档进行了适当修改,旨在介绍如何实现一个能够同时处理多个客户端请求的服务端程序。在前文中,我们探讨了单客户端访问的服务端实现,而本篇将深入讲解多客户端环境下的服务端设计与实现。 ... [详细]
  • 1、编写一个Java程序在屏幕上输出“你好!”。programmenameHelloworld.javapublicclassHelloworld{publicst ... [详细]
  • 本文详细探讨了在Java中如何将图像对象转换为文件和字节数组(Byte[])的技术。虽然网络上存在大量相关资料,但实际操作时仍需注意细节。本文通过使用JMSL 4.0库中的图表对象作为示例,提供了一种实用的方法。 ... [详细]
  • 如何使用Maven将依赖插件一并打包进JAR文件
    本文详细介绍了在使用Maven构建项目时,如何将所需的依赖插件一同打包进最终的JAR文件中,以避免手动部署依赖库的麻烦。 ... [详细]
  • Android 中的布局方式之线性布局
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • Zabbix自定义监控与邮件告警配置实践
    本文详细介绍了如何在Zabbix中添加自定义监控项目,配置邮件告警功能,并解决测试告警时遇到的邮件不发送问题。 ... [详细]
  • 本文通过分析一个具体的案例,探讨了64位Linux系统对32位应用程序的兼容性问题。案例涉及OpenVPN客户端在64位系统上的异常行为,通过逐步排查和代码测试,最终定位到了与TUN/TAP设备相关的系统调用兼容性问题。 ... [详细]
  • 根据官方定义,RxJava是一种用于异步编程和可观察数据流的API。其核心特性在于流式处理能力和丰富的操作符支持。 ... [详细]
author-avatar
悶得咪_438
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有