我做了这个函数,当你输入一些简短的东西时它和原始Java函数一样,但是如果我输入大于5-7个字符的东西 - 那么我得到一些真正的大数字。 (而不是正确的哈希码)
这是Java的哈希函数的公式:
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
Simplier one(仅适用于短字符串):
s = "abc" //String
n = 3 //Lenght of the String
s[0] = 'a'. ASCII code of 'a' = 97.
97 * (31 ^ (n - 1))
97 * (31 ^ (2))
97 * 961 = 93217
s[1] = 'b'. ASCII code of 'b' = 98.
98 * (31 ^ (n - 2))
98 * (31 ^ 1)
98 * 31 = 3038
s[2] = 'c'. ASCII code of 'c' = 99.
99 * (31 ^ (n - 3))
99 * (31 ^ 0)
99 * 1 = 99
93217 + 3038 + 99 = 96354 //
我想知道即使我输入一个巨大的字符串,Java如何使哈希变小。
Java's hashcode of "Hello" - 69609650
My hashcode of "Hello" - 69609650
Java's hashcode of "Welcome to Tutorialspoint.com" - 1186874997
My hashcode of "Welcome to Tutorialspoint.com" - 5.17809991536626e+43
如果我们将数字相加,哈希怎么可能是否定的?
答案 0 :(得分:3)
我怀疑您的实施(您尚未显示)使用BigInteger
或类似内容。 Java只使用int
- 所以当它溢出正31位整数的范围时,它会进入大的负整数,然后当你添加更多(正)值时,你最终会得到小的负数整数,然后是小的正整数,然后是大的正整数 - 然后回到大的负整数。
答案 1 :(得分:2)
字符串' hashCode
仅涉及int
加法和乘法,因此会产生int
,这可能会溢出(因此为负值)。
public int hashCode() {
int h = hash;
int len = count;
if (h == 0 && len > 0) {
int off = offset;
char val[] = value;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
根据您的5.17809991536626e+43
值,看起来您正在进行浮点计算(可能您使用Math.pow()
返回double
),这会为大数字提供不同的结果。
答案 2 :(得分:1)
String$hashCode()
的源代码:
1494 public int hashCode() {
1495 int h = hash;
1496 if (h == 0 && count > 0) {
1497 int off = offset;
1498 char val[] = value;
1499 int len = count;
1500
1501 for (int i = 0; i < len; i++) {
1502 h = 31*h + val[off++];
1503 }
1504 hash = h;
1505 }
1506 return h;
1507 }
int
是4个字节的有符号整数,它将在哈希计算期间溢出,产生一个可以为负的值,但始终由int
约束。