如何复写equals() 和 hashCode()

来源:互联网 发布:有关于人工智能的电影 编辑:程序博客网 时间:2024/06/03 23:37

覆写equals方法

1  使用instanceof操作符检查“实参是否为正确的类型”。

2  对于类中的每一个“关键域”,检查实参中的域与当前对象中对应的域值。

3. 对于非float和double类型的原语类型域,使用==比较;

4  对于对象引用域,递归调用equals方法;

5  对于float域,使用Float.floatToIntBits(afloat)转换为int,再使用==比较;

6  对于double域,使用Double.doubleToLongBits(adouble)转换为int,再使用==比较;

7  对于数组域,调用Arrays.equals方法。

覆写hashcode

1. 把某个非零常数值,例如17,保存在int变量result中;

2. 对于对象中每一个关键域f(指equals方法中考虑的每一个域):

3, boolean型,计算(f? 0 : 1);

4. byte,char,short型,计算(int);

5. long型,计算(int)(f ^ (f>>>32));

6. float型,计算Float.floatToIntBits(afloat);

7. double型,计算Double.doubleToLongBits(adouble)得到一个long,再执行[2.3];

8. 对象引用,递归调用它的hashCode方法;

9. 数组域,对其中每个元素调用它的hashCode方法。

10. 将上面计算得到的散列码保存到int变量c,然后执行result=37*result+c;

11. 返回result。


例如:

public class MyTest{
    private short ashort;
    private char achar;
    private byte abyte;
    private boolean abool;
    private long along;
    private float afloat;
    private double adouble;
    private Unit aObject;
    private int[] ints;
    private Test[]test;
 
    public boolean equals(Object o) {
       if (!(o instanceof Test))
           return false;
       Test test= (Test) o;
       return test.ashort == ashort
              && test.achar == achar
              && test.abyte == abyte
              && test.abool == abool
              && test.along == along
              && Float.floatToIntBits(test.afloat) == Float
                     .floatToIntBits(afloat)
              && Double.doubleToLongBits(test.adouble) == Double
                     .doubleToLongBits(adouble)
              && test.aObject.equals(aObject) 
              && equalsInts(test.ints)
              && equalstTest(test.units);
    }
 
    private boolean equalsInts(int[] aints) {
       return Arrays.equals(ints, aints);
    }
 
    private boolean equalsTest(test[] atest) {
       return Arrays.equals(test, atest);
    }
 
    public int hashCode() {
       int result = 17;
       result = 31 * result + (int) ashort;
       result = 31 * result + (int) achar;
       result = 31 * result + (int) abyte;
       result = 31 * result + (abool ? 0 : 1);
       result = 31 * result + (int) (along ^ (along >>> 32));
       result = 31 * result + Float.floatToIntBits(afloat);
       long tolong = Double.doubleToLongBits(adouble);
       result = 31 * result + (int) (tolong ^ (tolong >>> 32));
       result = 31 * result + aObject.hashCode();
       result = 31 * result + intsHashCode(ints);
       result = 31 * result + unitsHashCode(units);
       return result;
    }
 
    private int intsHashCode(int[] aints) {
       int result = 17;
       for (int i = 0; i < aints.length; i++)
           result = 31 * result + aints[i];
       return result;
    }
 
    private int testHashCode(Unit[] atest) {
       int result = 17;
       for (int i = 0; i < atest.length; i++)
           result = 31 * result + atest[i].hashCode();
       return result;
    }
}


此外,在使用Instanceof的时候要注意超类和子类的类型,有可能会引起返回为False的情况。

还有 在计算hash值的时候为什么要用31这个数字,我们来看这个要命的31这个系数为什么总是在里面乘啊乘的?为什么不适用32或者其他数字?

嘿嘿,31是个神奇的数字,因为任何数n * 31就可以被JVM优化为 (n << 5) -n,移位和减法的操作效率要比乘法的操作效率高的多,对左移现在很多虚拟机里面都有做相关优化,并且31只占用5bits!

大家都知道,计算机的乘法涉及到移位计算。当一个数乘以2时,就直接拿该数左移一位即可!选择31原因是因为31是一个素数!

所谓素数:

质数又称素数

素数在使用的时候有一个作用就是如果我用一个数字来乘以这个素数,那么最终的出来的结果只能被素数本身和被乘数还有1来整除!如:我们选择素数3来做系数,那么3*n只能被3和n或者1来整除,我们可以很容易的通过3n来计算出这个n来。这应该也是一个原因!


以上文章参考与http://blog.csdn.net/lifetragedy/article/details/9751079



0 0