早前曾经分享过一篇《TypeScript 实现 .NET 字符串HashCode算法》,将 .NET Framework 中曾使用的字符串哈希算法翻译成了 Typescript 表达。
有朋友向我咨询是否存在 Java 版的,其实是有的,而且也在生产运行了很多年,只是 Java 比较容易翻译此前我就没发出来,现在再额外补充一篇吧。
与Typescript那篇一样,首先是 C# 源码。
// HashUtils.cs
public sealed class HashUtils
{
private HashUtils() { }
/// <summary>
/// 计算哈希值
/// </summary>
/// <param name="text">对象字符串</param>
/// <returns>哈希结果</returns>
public static int CalcHashCode(string text)
{
var chars = Encoding.Unicode.GetBytes(text);
var half_pre = 0x15051505;
var half_post = half_pre;
var index = 0;
for (int i = text.Length; i > 0; i -= 4)
{
var data = new int[]
{
calc(chars, index + 3, 24) + calc(chars, index + 2, 16) + calc(chars, index + 1, 8) + calc(chars, index + 0, 0),
calc(chars, index + 7, 24) + calc(chars, index + 6, 16) + calc(chars, index + 5, 8) + calc(chars, index + 4, 0),
};
half_pre = (((half_pre << 5) + half_pre) + (half_pre >> 0x1b)) ^ data[0];
if (i <= 2)
{
break;
}
half_post = (((half_post << 5) + half_post) + (half_post >> 0x1b)) ^ data[1];
index += 8;
}
return half_pre + (half_post * 0x5d588b65);
}
private static int calc(byte[] bytes, int index, int offset)
{
if (index >= bytes.Length)
{
return 0;
}
return bytes[index] << offset;
}
}
然后下面是 Java 版
package com.luckystarry.utility;
import java.nio.charset.StandardCharsets;
public class HashUtils {
/**
* C-Shape 实现
*
* @param text 要计算哈希值的字符串
* @return 字符串的哈希值
*/
private static int getHashCode(String text) {
byte[] bytes = text.getBytes(StandardCharsets.UTF_16LE);
int[] ints = new int[bytes.length];
for (int i = 0; i < bytes.length; i++) {
ints[i] = bytes[i] & 0xff;
}
int half_pre = 0x15051505;
int half_post = half_pre;
int index = 0;
for (int i = text.length(); i > 0; i -= 4) {
int[] data = new int[] {
calc(ints, index + 3, 24) + calc(ints, index + 2, 16) + calc(ints, index + 1, 8)
+ calc(ints, index + 0, 0),
calc(ints, index + 7, 24) + calc(ints, index + 6, 16) + calc(ints, index + 5, 8)
+ calc(ints, index + 4, 0), };
half_pre = (((half_pre << 5) + half_pre) + (half_pre >> 0x1b)) ^ data[0];
if (i <= 2) {
break;
}
half_post = (((half_post << 5) + half_post) + (half_post >> 0x1b)) ^ data[1];
index += 8;
}
return (half_pre + (half_post * 0x5d588b65));
}
private static int calc(int[] ints, int index, int offset) {
if (index >= ints.length) {
return 0;
}
return ints[index] << offset;
}
}