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

今天用到了HashMap,HashMap<GPSPoint, Integer>

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

Map<GPSPoint, Integer> map=new HashMap<GPSPoint, Integer>();
		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;




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值