Java hashCode() 方法

在 java.lang.Object 类中有几个个非常重要的方法,我们今天来讨论下 hashCode() 这个方法。

什么是 Hash

Hash 中文叫做哈希也可以叫做散列,使用 Hash 的算法生成字符串或者数字的方法就可以称为 Hash 算法,或者散列算法。

如果还不太明白的话,考虑下 MD5。MD5 就是典型的哈希算法,通过 MD5 算法,不管你是输入字符串,图片,二进制文件,都能获得一个字符串。

获得这个字符串的算法就是 Hash 算法。

为什么要 Hash

我们在这里不打算讨论复杂的 Hash 算法或者 Hash 算法怎么去计算的。因为这样的话,你可能需要很长的时间才能搞明白到底怎么算出来的。

使用 Hash 算法的目的就是为了将获得的数据摘要信息尽量分散,并且尽量的不重复,同时还需要保证相同数据的 Hash 结果是相同不能变化的。

不管你将相同数据 Hash 多少遍,只要数据相同,那么 Hash 必须是相同的。

哈希碰撞

在现实生活中,不同数据的 Hash 结果可能是相同的。

考察下面的代码:

        logger.debug("HashCode AaAaAa - {}", "AaAaAa".hashCode());
        logger.debug("HashCode BBAaBB - {}", "BBAaBB".hashCode());

上面代码输出的结果是相同的,这种情况就是哈希碰撞( Hash collision)。

很遗憾,这种哈希碰撞在现实中是不能避免的。

常用的哈希算法

常用的 Hash 算法有下面的一些算法。

MD5 的算法已经不是安全的 Hash 算法了,在密码学和开发中,已经逐步推荐使用 SHA-256 算法了。

算法 输出长度(位) 输出长度(字节)
MD5 128 bits 16 bytes
SHA-1 160 bits 20 bytes
RipeMD-160 160 bits 20 bytes
SHA-256 256 bits 32 bytes
SHA-512 512 bits 64 bytes

根据碰撞概率,哈希算法的输出长度越长,就越难产生碰撞,也就越安全。

Java 的 hashCode()

Java 中的 hashCode() 方法返回的数据类型是 int 类型。

下面以 String 对象的 hashCode 为例,官方解释中有关 String 对象 Hash 算法计算方式是:

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

针对输入字符串是不是 UTF16,将会有不同的计算方法。

IntelliJ IDEA 重写 Hash 算法

如果你不想使用 Java Object 对象中的 Hash 算法,你可以在你的对象中重写 Hash 算法。

在 IntelliJ IDEA 输入快捷键 Alt+Insert,这个将会弹出快速生成方法的选择项。

hash-02

随后将会提示你选用何种方法来创建 hashCode() 方法。你可以选择使用 JDK 自带的,你也可以选择使用 Apache Commons-lang 的方法来重写方法。当然,你也可以使用其他的一些方法来写,不管哪个方法来写,原理都是相通的。

hash-03

选择变量,在完成上面的方法选择后,将会提示你选择变量。

将需要创建的变量选择,然后下一步。

hash-04

同时还需要你选择非空的字段,你可以默认选择也可以不选择。

hash-05

如下,你可以看到使用 JDK 生成的默认的 hashCode 方法。

    @Override
    public int hashCode() {
        return Objects.hash(title, topic_id, raw, category, target_recipients, archetype, created_at);
    }

如果你根据使用的是 Apache 的 Commons 生成的话,结果有所不同。

可以在 IDE 中自行研究下。

需要注意的是,在 hashCode 中,你可能会看到数字 17,31,37。

其实这些数字就是素数了,在 Java 面试的时候可能会有一道题目就是找出 100 以内的素数。

因为 Hash 算法在很多时候其实也可以用于密码学中,密码学的很多基础研究就是对素数的研究。

网络中广泛使用的RSA算法,就是基于素数性质的重要应用。

因此在 hashCode 的方法中,你能看到上面的数字,这个就是有关素数算法的实际应用之一。因为涉及到很多密码学的知识,我们这里就不实际展开了。

通过上面的说明,我们就能够在 Java 中对对象或者数据进行 Hash。

哈希算法和应用是 Java Hashmap 的基础,因此 hashCode 方法在 Java 中也会作为基础方法存在。