JDK1.8中的哈希散列算法

本文详细介绍了JDK1.8中不同数据类型的哈希散列算法,包括int、float、long、double以及String类型的处理方式。对于int和float,直接返回其值;long和double通过位运算确保每一位参与运算;String类型则利用字符乘以特定基数(如31)进行计算,以提高效率。文章还探讨了为何选择31作为基数的原因,并提及自定义对象的哈希计算方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、int类型、float类型

int类型很简单,直接返回该int即可

public static int hashCode(int value) {
    return value;
}

float类型把它转为字节,再将字节转为int类型即可

public static int hashCode(float value) {
    return floatToIntBits(value);
}

二、long类型、double类型

long类型和double类型由于都是8个字节(64位),无法直接转换位4个字节的int类型,并且在hash算法中,尽量要做到每一位都参与运算,于是我们先将它无符号右移32位,即将它的高32位复制到低32位,并且在高32位补0,然后再与它本身做异或运算,再把结果强转为int类型即可

public static int hashCode(long value) {
    return (int)(value ^ (value >>> 32));
}

double也是同理,先将double转为字节,然后再进行上述操作

public static int hashCode(double value) {
    long bits = doubleToLongBits(value);
    return (int)(bits ^ (bits >>> 32));
}

三、String类型

首先我们先想一个问题,7346这个数字如何表示呢?很容易想到:

7346 = 7 ∗ 1 0 3 + 3 ∗ 1 0 2 + 4 ∗ 1 0 1 + 6 ∗ 1 0 0 7346 = 7*10^3 + 3*10^2 + 4*10^1 + 6*10^0 7346=7103+3102+4101+6100

字符串的hash算法也是类似的,例如我们要对"hello"这个字符串做hash,那它的计算过程是:

h a s h ( “ h e l l o ” ) = ‘ h ’ ∗ n 4 + ‘ e ’ ∗ n 3 + ‘ l ’ ∗ n 2 + ‘ l ’ ∗ n 1 + ‘ o ’ ∗ n 0 hash(“hello”) = ‘h’ * n^4 + ‘e’*n^3 + ‘l’*n^2 + ‘l’ *n^1 + ‘o’ * n^0 hash(hello)=hn4+en3+ln2+ln1+on0

在这个运算中,其实有一些的运算是多余的,例如计算 n 4 n^4 n4,我们完全可以使用后面计算的 n 3 ∗ n n^3 * n n3n来得到, n 3 n^3 n3也是同理,所以上面那个计算过程就等价于:

( ( ( ( ‘ h ’ ∗ n + ‘ e ’ ) ∗ n ) + ‘ l ’ ) ∗ n + ‘ l ’ ) ∗ n + ‘ o ’ ((((‘h’ * n + ‘e’)*n)+‘l’)*n+‘l’)*n+‘o’ ((((hn+e)n)+l)n+l)n+o

解决了计算过程的问题,那接下来问题就来了,n取多少合适呢?
在JDK内部,它的n取值为31,为什么是31呢?
31是一个很神奇的数,它是一个奇素数,并且任何一个数i * 31 就等于 (i << 5) - i,要知道,位运算要比乘法运算效率高的多,JVM也会针对这个计算过程自动做优化
具体可以看一下这个博客,里面分析的很到位

看一下JDK1.8中String类的实现,实际上就是计算了一次上述的公式:

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;
}

四、自定义对象

自定义对象的hash方法与String类似,可以使用该对象的所有属性依次计算其hash值后,再套用上面说的公式返回最终的hash值
可以查看一下JDK的实现

java.util.Objects.hash方法:
public static int hash(Object... values) {
    return Arrays.hashCode(values);
}

java.util.Arrays.hashCode方法:
public static int hashCode(Object a[]) {
    if (a == null)
        return 0;

    int result = 1;

    for (Object element : a)
        result = 31 * result + (element == null ? 0 : element.hashCode());

    return result;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值