java-equals和hashcode方法

时间:2022-04-11 16:14:22
1、hashcode的作用:hashcode可以把对象进行分类(hashMap,hashTable,hashSet),相同的为一类,放在同一个篮子中。
2、equals的作用,在同一个篮子中(hashcode相同),比较两个对象是否在值上相同(已重写)。
3、hashCode的重写方式:
公约:
第一:在某个运行时期间,只要对象的(字段的)变化不会影响equals方法的决策结果,那么,在这个期间,无论调用多少次hashCode,都必须返回同一个散列码。
第二:通过equals调用返回true 的2个对象的hashCode一定一样。
第三:通过equasl返回false 的2个对象的散列码不需要不同,也就是他们的hashCode方法的返回值允许出现相同的情况。
总结一句话:等价的(调用equals返回true)对象必须产生相同的散列码。不等价的对象,不要求产生的散列码不相同。
具体重写方式:
要重写自己的hashCode方法并没有什么绝对正确的答案,但是我们的目标是:不相等的对象尽可能有不同的hashCode,而且必须满足的一个通用约定是:相等的对象应该具有相同的hashCode。下面介绍一种hashCode的实现方式,这种实现方式对一般的程序来说足够了,至于如何实现更完美的hashCode方法就留给数学家或者理论家去讨论吧。
第一步: 定义一个初始值,一般来说取17
int result = 17;
第二步: 分别解析自定义类中与equals方法相关的字段(假如hashCode中考虑的字段在equals方法中没有考虑,则两个equals的对象就很可能具有不同的hashCode)
    情况一:字段a类型为boolean 则[hashCode] = a ? 1 : 0;
    情况二:字段b类型为byte/short/int/char, 则[hashCode] = (int)b;
    情况三:字段c类型为long, 则[hashCode] = (int) (c ^ c>>>32);
    情况四:字段d类型为float, 则[hashCode] = d.hashCode()(内部调用的是Float.hashCode(d), 而该静态方法内部调用的另一个静态方法是Float.floatToIntBits(d))
    情况五:字段e类型为double, 则[hashCode] = e.hashCode()(内部调用的是Double.hashCode(e), 而该静态方法内部调用的另一个静态方法是Double.doubleToLongBits(e),得到一个long类型的值之后,跟情况三进行类似的操作,得到一个int类型的值)
    情况六:引用类型,若为null则hashCode为0,否则递归调用该引用类型的hashCode方法。
    情况七:数组类型。(要获取数组类型的hashCode,可采用如下方法:s[0]*31 ^ (n-1) + s[1] * 31 ^ (n-2) + ..... + s[n-1], 该方法正是String类的hashCode实现所采用的算法)
第三步: 对于涉及到的各个字段,采用第二步中的方式,将其 依次 应用于下式:
result = result * 31 + [hashCode];
补充说明一点:如果初始值result不取17而取0的话,则对于hashCode为0的字段来说就没有区分度了,这样更容易产生冲突。比如两个自定义类中,一个类比另一个类多出来一个或者几个字段,其余字段全部一样,分别new出来2个对象,这2个对象共有的字段的值全是一样的,而对于多来的那些字段的值正好都是0,并且在计算hashCode时这些多出来的字段又是最先计算的,这样的话,则这两个对象的hashCode就会产生冲突。还是那句话,hashCode方法的实现没有最好,只有更好。
4、equals方法的重写方式
公约:
自反性 :  x.equals(x) 一定是true
对null :  x.equals(null) 一定是false
对称性 :  x.equals(y)  和  y.equals(x)结果一致
传递性:  a 和 b equals , b 和 c  equals,那么 a 和 c也一定equals。
一致性:  在某个运行时期间,2个对象的状态的改变不会不影响equals的决策结果,那么,在这个运行时期间,无论调用多少次equals,都返回相同的结果。
具体重写方式:
hashCode()和equals()方法,定义在Object类中,这个类是所有类的基类,所以所有的java类都继承了这两个方法。
        hashCode()方法用来给对象获取唯一的一个整数。这个整数被存储在HashTable类似的结构中的位置。默认的,Object类的hashCode()方法返回这个对象存储的内存地址的编号。
        重写equals()方法必须要重写hashCode()方法。 if two objects are equal, equal objects must produce the same hash code。 However, the third point elaborates that unequal objects need not produce distinct hash codes.
Summed up,equal objects must produce the same hash code as long as they are equal, however unequal objects need not produce distinct hash codes.


重写方法

public class Test  
2.  {  
      private int num;  
      private String data;  
  
      public boolean equals(Object obj)  
      {  
          if(this == obj)  
              return true;  
         if((obj == null) || (obj.getClass() != this.getClass()))  
             return false;  
         // object must be Test at this point  
         Test test = (Test)obj;  
         return num == test.num &&  
         (data == test.data || (data != null && data.equals(test.data)));  
     }  
  
     public int hashCode()  
     {  
         int hash = 7;  
         hash = 31 * hash + num;  
         hash = 31 * hash + (null == data ? 0 : data.hashCode());  
         return hash;  
     }  
  
     // other methods  
 }