Java String.hashCode()方法推导解析及Cat示例计算疑问解答
解惑Java String.hashCode()中"Cat"的哈希值计算过程
别担心,我来帮你把这个计算过程拆解得明明白白!你的核心问题是记错了字符对应的Unicode(ASCII)值,咱们一步步来:
第一步:确认字符的正确Unicode值
你之前用的37、66、85是完全错误的,正确的ASCII(Unicode的子集)值应该是:
- 大写字母'C':
67 - 小写字母'a':
97 - 小写字母't':
116
你可以通过Java代码快速验证:
System.out.println((int)'C'); // 输出67 System.out.println((int)'a'); // 输出97 System.out.println((int)'t'); // 输出116
第二步:代入公式计算
课本给出的公式是对的:S₀×31^(n-1) + S₁×31^(n-2) + … + S(n-1),对于"Cat"这个长度为3的字符串,n=3,计算过程如下:
- 先计算31的幂次:
31² = 961,31¹=31,31⁰=1 - 代入字符值:
'C' × 31² = 67 × 961 = 64387'a' × 31 = 97 × 31 = 3007't' × 1 = 116 × 1 = 116
- 求和:
64387 + 3007 + 116 = 67510,和课本的结果完全一致!
额外补充:为什么Java选择31作为乘数?
Java里用31不是随便选的,主要有两个原因:
- 31是质数:质数作为乘数能有效减少不同字符串产生相同哈希值的概率(哈希碰撞)。
- 计算高效:31可以用位运算快速计算:
31 * i = (i << 5) - i,因为2^5=32,32i -i=31i,比直接乘法更快。
关于String.hashCode()的额外细节
在Java的实际实现中,哈希值的计算是迭代进行的,避免直接计算大幂次(防止溢出,但Java的int溢出是允许的,属于设计的一部分),大致逻辑如下:
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; }
你可以用这个迭代方式再算一遍"Cat":
- 初始h=0
- 第一步:h = 31*0 + 67 = 67
- 第二步:h = 31*67 + 97 = 2077 + 97 = 2174
- 第三步:h = 31*2174 + 116 = 67394 + 116 = 67510
结果和之前完全一样!
内容的提问来源于stack exchange,提问作者Jack White
相关产品推荐
相关产品推荐

