两个不同长度的字符串可以具有相同的哈希码吗?

Can two strings of different length have the same hashcode?

虽然我知道两个不同的字符串可以 return 相同的哈希码,但我一直找不到关于两个不同长度的字符串的信息。这是否可能,如果可以,将不胜感激。这是使用 java 哈希码函数,以防发生任何变化。

哈希码分布在 int 的 space 上。 int 只有 2^32 = ~4 billion 个可能的值。可能的字符串远不止这个数量,因此根据鸽巢原理,必须存在多个具有相同哈希码的字符串。

但是,这并不能证明不同长度的字符串可能具有相同的哈希码,如下所述。 Java 使用公式 s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] 对字符串进行哈希处理。知道了这一点,构造具有相同哈希码的不同长度的字符串就很容易了:

String s1 = "[=14=]1!";String s2 = "@";。然后 s1.length() != s2.length()s1.hashCode() == '[=17=]1' * 31 + '!' == 1 * 31 + 33 == 64 == s2.hashCode() == '@' == 64

但是,让我再说一遍,int 有超过 4 亿 个可能值,所以你的碰撞概率很低,虽然没有低到你可能会想,因为 Birthday Paradox,这让你在大约 77K 哈希后有大约 50% 的机会发生冲突(假设哈希是随机分布的,这实际上取决于你的数据 - 如果你主要处理非常小长度的字符串,你会更频繁地发生冲突)。但是,每个使用散列处理的数据结构都必须处理冲突(例如,一种常见的方法是在每个散列位置使用链表),或者处理数据丢失(例如,在布隆过滤器中)。

是的,这可能会发生。

一些相当简单的例子:

  • 初始零值字符不影响散列码,因此(例如)"foo""[=11=]foo""[=12=][=12=]foo" 等都具有相同的散列-code.
  • 在添加下一个字符之前,每个字符只乘以 31;所以(例如)双字符字符串 new String(new char[] { 12, 13 }) 与单字符 new String(new char[] { 12 * 31 + 13 }) 具有相同的哈希码(我在其中任意选择了 1213;相同适用于任何其他值,只要 12 * 31 + 13 模拟保持在双字节无符号整数范围内)。

但这些只是一些易于构建的示例。还有很多字符串对恰好具有相同的哈希码,尽管它们之间没有明显的关系。