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

重写equals()方法和hashcode()方法

今天用到了HashMap,HashMap<GPSPoint,Integer>但是当新建另外一个GPSPoint的时候却取不到对应的valueMap<GPSPoin

今天用到了HashMap,HashMap

但是当新建另外一个GPSPoint的时候却取不到对应的value

Map map=new HashMap();
for(int i=0;i<5;i++){
GPSPoint p=new GPSPoint(i,i,i,i);
map.put(p, i);
}

GPSPoint p=new GPSPoint(2,2,2,2);
int i=map.get(p);
System.out.println(i);

深入了解了才知道每个对象实例对应一个hashCode,对应着内存地址

而hashMap通过key查找是找hashCode

更加深入了解,请见另外一篇     深入解析Java对象的hashCode和hashCode在HashMap的底层数据结构的应用


重写hashCode()时最重要的原因就是

无论何时,对同一个对象调用hashCode()都应该生成同样的值。如果在将一个对象用put()方法添加进HashMap时产生一个hashCode()值,而用get()取出时却产生了另外一个 hashCode()值,那么就无法重新取得该对象了。所以,如果你的hashCode()方法依赖于对象中易变的数据,那用户就要小心了,因为此数据发生变化时,hashCode()就会产生一个不同的hash码,相当于产生了一个不同的“键”。 Object的hashCode()方法,返回的是当前对象的内存地址。下次如果我们需要取一个一样的“键”对应的键值对的时候,我们就无法得到一样的hashCode值了。因为我们后来创建的“键”对象已经不是存入HashMap中的那个内存地址的对象了。 


下面看看怎么重写hashCode

1、我们应该先了解java判断两个对象是否相等的规则。

      在java的集合中,判断两个对象是否相等的规则是:

      1  首先,判断两个对象的hashCode是否相等

      2  如果不相等,认为两个对象也不相等
      3  如果相等,则判断两个对象用equals运算是否相等 
      4  如果不相等,认为两个对象也不相等 
      5  如果相等,认为两个对象相等

    我们在equals方法中需要向下转型,效率很低,所以先判断hashCode方法可以提高效率


  1. package test;  
  2.   
  3. /** 
  4.  * 判断两个对象的相等,首先判断hashcode,再equals 
  5.  * 重写了equals,一般伴随着重写hashcode 
  6.  *  
  7.  * 重写equals一般要遵从如下的原则: 
  8.  *  1、一致性 2、对称性 3、传递性 4、自反性 5、非空性 
  9.  *   
  10.  * 重写hashcode遵从的步骤: 
  11.  * 1、如果该域是boolean类型,则计算(f?1:0) 
  12.  * 2、如果是byte、char、short、int则转换成int类型 
  13.  * 3、如果是long,则计算(int)(f^(f>>>32)) 
  14.  * 4、如果是float,则计算Float.floatToIntBits(f) 
  15.  * 5、如果是double,则Double.doubleToLongBits(f),然后再按照步骤3 
  16.  * 6、如果是对象,就用equals方法中递归的调用了对象的equals方法,则递归的调用hashcode 
  17.  * 7、如果是数组,一般用Arrays.hashCode 
  18.  * 最后调用公式:result = 31 * result + c 
  19.  * @author zKF57533 
  20.  */  
  21. public class Student {  
  22.     private String name;  
  23.     private Integer age;  
  24.     private String identityId;  
  25.       
  26.       
  27.     public Student(){};  
  28.       
  29.     public Student(String name, String identityId) {  
  30.         super();  
  31.         this.name = name;  
  32.         this.identityId = identityId;  
  33.     }  
  34.     public String getIdentityId() {  
  35.         return identityId;  
  36.     }  
  37.     public void setIdentityId(String identityId) {  
  38.         this.identityId = identityId;  
  39.     }  
  40.       
  41.     public String getName() {  
  42.         return name;  
  43.     }  
  44.     public void setName(String name) {  
  45.         this.name = name;  
  46.     }  
  47.     public Integer getAge() {  
  48.         return age;  
  49.     }  
  50.     public void setAge(Integer age) {  
  51.         this.age = age;  
  52.     }  
  53.     @Override  
  54.     public String toString() {  
  55.         return "Student [age=" + age + ", name=" + name + "]";  
  56.     }  
  57.       
  58.     @Override  
  59.     public boolean equals(Object o){  
  60.           
  61.         //第一步判断是否是当前对象的引用  
  62.         if(this == o){  
  63.             return true;  
  64.         }  
  65.           
  66.         //第二步判断是否是此类型  
  67.         if(!(o instanceof Student)){  
  68.             return false;  
  69.         }  
  70.           
  71.         //第三步将o转换成此类型  
  72.         Student s = (Student)o;  
  73.           
  74.         //第四部判断用来决定对象相等的关键字段  
  75.         return this.name.equals(s.getName()) && this.identityId.equals(s.getIdentityId());  
  76.     }  
  77.       
  78.     @Override  
  79.     public int hashCode(){  
  80.         int result = 19;//此值可以是任选的  
  81.         result = 31 * result + name.hashCode();  
  82.         result = 31 * result + identityId.hashCode();  
  83.         return result;  
  84.     }  
  85.       
  86.     public static void main(String[] args) {  
  87.         Student s1 = new Student("name1","1234");  
  88.         Student s2 = new Student("name1","1234");  
  89.         System.out.println(s1.equals(s2)); //true  
  90.     }  
  91.       
  92. }  

(1)为对象内每个有意义的属性f(即每个用作equals()比较标准的属性)计算出一个int类型的hashCode值。计算方法如下表所示: 
属性类型
计算方式
boolean
hashCode = (f ? 0 : 1);
整数类型(byte、short、char、int)
hashCode = (int)f;
long
hashCode = (int)(f ^ (f >>>32));
float
hashCode = Float.floatToIntBits(f);
double
long l = Double.doubleToLongBits(f);
hashCode = (int)(l ^ (l >>> 32));
普通引用类型
hashCode = f.hashCode();
(2)使用第1步计算出来多个hashCode组合计算出一个hashCode值返回。例如如下代码:
return f1.hashCode() + (int)f2;
如果为了避免直接相加产生偶然相等(两个对象的f1、f2属性并不相等,但他们的和恰好相等),可以通过为各属性乘以任意一个质数后再相加。例如如下代码:
return f1.hashCode() * 17+ (int)f2 * 13;





推荐阅读
  • 图像因存在错误而无法显示 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • Java SE从入门到放弃(三)的逻辑运算符详解
    本文详细介绍了Java SE中的逻辑运算符,包括逻辑运算符的操作和运算结果,以及与运算符的不同之处。通过代码演示,展示了逻辑运算符的使用方法和注意事项。文章以Java SE从入门到放弃(三)为背景,对逻辑运算符进行了深入的解析。 ... [详细]
  • ***byte(字节)根据长度转成kb(千字节)和mb(兆字节)**parambytes*return*publicstaticStringbytes2kb(longbytes){ ... [详细]
author-avatar
苏绿儿520
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有