您的位置:首页 > 其它

equals()和hashcode()用法

2013-08-23 17:30 127 查看
通常情况下,class覆写equals()的同时也会覆写hashcode()方法, 通常保证两个对象equals,那么他们的hashcode相等。这样做的目的是为了和Java的结合框架协同工作,因为我们自己定义的类完全可以覆写equals方法,但是不覆写hashCode,尽管我们可以这样做,但是这样做是不合理的,他会为我们的程序埋下错误隐患。虽然java没有从在编译器对上面的说法进行控制,但是上面的说法是我们在设计类的时候应该遵循的规则。

覆写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=31*result+c;

11. 返回result。

当改写equals()的时候,总是要改写hashCode()

根据一个类的equals方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据Object.hashCode方法,它们仅仅是两个对象。因此,违反了“相等的对象必须具有相等的散列码”。

两个对象如果equals那么这两个对象的hashcode一定相等,如果两个对象的hashcode相等那么这两个对象是否一定equals?

回答是不一定,这要看这两个对象有没有重写Object的hashCode方法和equals方法。如果没有重写,是按Object默认的方式去处理。

试想我有一个桶,这个桶就是hashcode,桶里装的是西瓜我们认为西瓜就是object,有的桶是一个桶装一个西瓜,有的桶是一个桶装多个西瓜。

比如String重写了Object的hashcode和equals,但是两个String如果hashcode相等,那么equals比较肯定是相等的,但是“==”比较却不一定相等。如果自定义的对象重写了hashCode方法,有可能hashcode相等,equals却不一定相等,“==”比较也不一定相等。

为什么我们在定义hashcode时如: h = 31*h + val[off++];
要使用31这个数呢?

public int hashCode() {

int h = hash;

int len = count;

if (h == 0 && len > 0) {

int off = offset;

char val[] = value;

for (int i = 0; i < len; i++) {

h = 31*h + val[off++];

}

hash = h;

}

return h;

}

来看一段hashcode的覆写案例:

其实上面的实现也可以总结成数数里面下面这样的公式:

s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]

我们来看这个要命的31这个系数为什么总是在里面乘啊乘的?为什么不适用32或者其他数字?

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

所谓素数:

质数又称素数

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

在存储数据计算hash地址的时候,我们希望尽量减少有同样的hash地址,所谓“冲突”。

31是个神奇的数字,因为任何数n * 31就可以被JVM优化为 (n << 5) -n,移位和减法的操作效率要比乘法的操作效率高的多,对左移现在很多虚拟机里面都有做相关优化,并且31只占用5bits!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: