Hash的计算方案





一个好的散列函数通常倾向于“为不相等的对象产生不相等的散列码”。这正是hashCode约定中第三条的含义。理想情况下,散列函数应该把集合中不相等的实例均匀地分布到所有可能的散列值上。要想完全达到这种理想的情形是非常困难的。幸运的是,相对接近这种理想情形则不太困难。下面给出一种简单的解决办法:
1、把某个非零的常数值,比如说17,保存在一个名为result的int类型的变量中。
2、对于对象中的每个关键域f(指equals方法中设计的每个域),完成以下步骤:
a.为该域计算int类型的散列码c:
i.如果该域是boolean类型,则计算(f ? 1 : 0)。
ii.如果该域是byte、char、short或则int类型,则计算(int)f.
iii.如果该域是long类型,则计算(int)(f ^ (f >>> 32)).
iv.如果该域是float类型,则计算Float.floatToIntBits(f).
v.如果该域是double类型,则计算Double.doubleToLongBits(f),然后按照步骤2.a.iii,为得到的long类型值计算散列码。
vi.如果该域是一个对象引用,并且该类的equals方法通过递归地调用equals的方式来比较这个域,则同样为这个域递归地调用hashCode。如果需要更复杂的比较,则为这个域计算一个“范式”,然后针对这个范式调用hashCode。如果这个域的值为null,则返回0(或则其他某个常数,但通常是0)。
vii.如果该域是一个数组,则要把每一个元素当作单独的域来处理。也就是说,递归地调用上述规则,对每个重要的元素计算一个散列码,然后组合起来。或则通过Arrays.hashCode()方法。

b.把计算得到的散列码c合并到result中:
result = 31 * result + c;

3、返回result。
4、编写测试单元,进行校验正确性。

Code:

private volatile int hashCode;
private int intElement;
private boolean booleanElement;
private char charElement = 'a';
private long longElement = 3333L;
private float floatElement = 33F;
private double doubleElement = 33D;
private String strElement = "string";
private final String[] strArray = new String[]{"A", "B"};

Override: hashCode

@Override
public int hashCode() {
    int result = hashCode;
    if(result == 0){
        result = 17;
        result = 31 * result + intElement;

        result = 31 * result + (booleanElement ? 1 : 0);
        result = 31 * result + ((int)charElement);
        result = 31 * result + ((int)(longElement ^ (longElement >>> 32)));
        result = 31 * result + Float.floatToIntBits(floatElement);
        long doubleLongBits = Double.doubleToLongBits(doubleElement);
        result = 31 * result + ((int) (doubleLongBits ^ (doubleLongBits >>> 32)));
        result = 31 * result + strElement.hashCode();
        result = 31 * result + Arrays.hashCode(strArray);
    }
    return result;
}

hashCode的约定条件:
1、在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法都必须始终如一地返回同一个整数。在同一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。

2、如果两个对象根据equals方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。

3、如果两个对象根据equals方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode的方法,则不一定要产生不同的整数结果。但是程序员应该知道,给不相等的对象产生截然不同的整数结果,有可能提高散列列表的性能。


源自《Effective Java》 Joshua Bloch著一书。
特此感谢!并记录以作参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值