热门标签 | 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;





推荐阅读
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 面向对象之3:封装的总结及实现方法
    本文总结了面向对象中封装的概念和好处,以及在Java中如何实现封装。封装是将过程和数据用一个外壳隐藏起来,只能通过提供的接口进行访问。适当的封装可以提高程序的理解性和维护性,增强程序的安全性。在Java中,封装可以通过将属性私有化并使用权限修饰符来实现,同时可以通过方法来访问属性并加入限制条件。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 数组的排序:数组本身有Arrays类中的sort()方法,这里写几种常见的排序方法。(1)冒泡排序法publicstaticvoidmain(String[]args ... [详细]
author-avatar
faithKOBE
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有