天天看点

对于所有对象都通用的方法 - 覆盖equals时总要覆盖hashCode

知识点:

1.hashCode的规范

2.为什么要覆盖hashCode

3.hashCode的写法

4.Java类库中的hashCode方法

1.hashCode的规范

a.应用程序执行的时候,如果equals方法的比较操作所用到的信息没有被修改,那么对于这个对象的多次调用,hashCode的值应该是不变的。

b.如果对象的equals相等,hashCode也必须相等

c.如果对象的equals不相等,hashCode可以相等,也可以不相等,但不等最好,这样可以提高散列表的性能。(对散列表的知识,我后面的文章会详细讲解)。

2.为什么要覆盖hashCode

如果你的对象想要和散列表的结构一起使用,就需要覆盖hashCode,不然是不能作用Map的key。

3.hashCode的写法

如果为boolean类型,则计算 f ? 1 : 0

如果为byte、char、short或者int类型,则计算 (int)f

如果为long类型,则计算 (int)(f ^ (f >>> 32))

如果为float类型,则计算Float.floatToIntBits(f)

如果为double类型,则计算Double.doubleToLongBits(f),然后再按long类型计算

如果为对象引用,并且该类的equals方法递归的调用了equals方法来比较这个域,则同样为这个域递归的调用hashCode;否则需要对这个对象计算一个”范式”,针对这个”范式”调用hashCode。如果该对象为null,则返回0

如果为数组,则把每个元素当成单独的域处理,或者使用Arrays.hashCode方法

按照上面的规则来计算散列码,基本上可以实现equals方法不同,hashCode就不同

4.Java类库中的hashCode方法

看下面Object,Boolean,String,Integer的hashCode方法,Object的hashCode方法是一个本地方法,返回是对象的地址值,Integer就是返回一个本身的value, String类的hashCode,他只会计算一次,String是不可变的,计算多次只会影响性能,没有意义,计算方式大家有兴趣可以研究一下,Boolean的hashCode,true返回1231,false返回1237,两个质数。java类库的hashCode方法不尽相同,好的散列函数能够提高散列表的性能。

Object类的hashCode方法
public native int hashCode();

Integer类的hashCode方法
public int hashCode() {
    return value;
}

String类的hashCode方法
public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

Boolean类的hashCode方法
public static int hashCode(boolean value) {
    return value ? 1231 : 1237;
}