繁体   English   中英

为什么以下三个字符串的哈希码相同?

[英]Why the following three strings's hashcode are same?

在阅读了JDK的源代码之后,我仍然惊讶于字符串"AaAa", "AaBB" and "BBBB"具有相同的哈希码。

JDK的来源如下:

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;

任何人都可以澄清吗?

因为这就是定义要为String计算哈希码的方式

字符串对象的哈希码计算为

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

所以:

  • 对于AaAa65*31^3 + 97*31^2 + 65*31 + 97 = 2031744
  • 对于AaBB65*31^3 + 97*31^2 + 66*31 + 66 = 2031744
  • 对于BBBB66*31^3 + 66*31^2 + 66*31 + 66 = 2031744

因为概率

可能有大约40亿个哈希码( Integer.MIN_VALUE -> Integer.MAX_VALUE )和基本上无限的字符串。 必然会有碰撞 实际上, 生日问题向我们显示任意碰撞的可能性很高,仅需要〜77,000个字符串 -如果哈希函数具有极高的熵,而事实并非如此,那就行了。

也许您在考虑加密散列函数

对消息进行很小的更改就应该广泛更改哈希值,以使新的哈希值看起来与旧的哈希值不相关

在这种情况下, Object.hashCode并非设计用于加密目的。

另请参见Java的hashCode()有多安全?

他们的哈希码是

AaAa: ((65 * 31 + 97) * 31 + 65) * 31 + 97 = 2.031.744
AaBB: ((65 * 31 + 97) * 31 + 66) * 31 + 66 = 2.031.744
BBBB: ((66 * 31 + 66) * 31 + 66) * 31 + 66 = 2.031.744

这就是数学的方式,没什么可混淆的。
请注意,97和66之间恰好是31的区别,这就是使这些哈希码排列得如此好的原因。

这是来自Java文档中的Object#hashCode方法的描述:

在Java应用程序执行期间,只要在同一对象上多次调用它, hashCode方法就必须一致地返回相同的整数,前提是不修改该对象的equals比较中使用的信息。此整数不必与一个整数保持一致一个应用程序的执行到同一应用程序的另一个执行。

如果根据equals(Object)方法,两个对象相等,则在两个对象中的每个对象上调用hashCode方法必须产生相同的整数结果。

根据java.lang.Object#equals(java.lang.Object)方法,如果两个对象不相等,则不需要在两个对象中的每个对象上调用hashCode方法必须产生不同的整数结果。 但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

因此, String类的实现也保持了上述特征。这是正常现象。

有几种类型的哈希函数具有不同的设计和性能标准。

  1. 用于索引的哈希函数(例如关联数组和类似用法)可能会发生频繁冲突而不会出现问题,因为哈希表代码将随后以某种名称处理该代码,例如将其放入列表或重新哈希。 这就是时间的性能。 Java hash()似乎是这种类型的

  2. 另一类函数,例如SHA *等加密哈希,以哈希性能为代价,努力避免冲突。

  3. 第三种散列函数是密码验证器散列,密码散列被设计为非常慢(通常为100毫秒左右),并且可能需要大量内存,因此不会出现频繁冲突。 这里的目的是要使蛮力攻击花费尽可能长的时间以至于不可行。

根据用途选择哈希的类型和特征。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM