【发布时间】:2014-01-13 19:34:59
【问题描述】:
在番石榴代码(我认为这是高质量代码的示例之一)中,我发现了以下片段:
// If the cachedHashCode is 0, it will always be recalculated, unfortunately.
private transient int cachedHashCode;
public final int hashCode() {
// Racy single-check.
int code = cachedHashCode;
if (code == 0) {
cachedHashCode = code = element.hashCode();
}
return code;
}
所以“如果 cachedHashCode 为 0,它总是会被重新计算,不幸的是”。另一个例子是JDKString.hashCode:
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;
}
它也尝试计算一次哈希码,但如果String的hashCode为0则失败(此类字符串的示例为"\0")。
避免此类重新计算的简单解决方案是增加对计算的额外检查:
if (hash == 0) hash++;
虽然在一般情况下它会稍微减慢hashCode 的计算速度,但这个技巧可以避免在反复计算时(并且缓慢(例如对于长字符串))一次又一次地计算最坏的情况。
为什么在 guava ImmutableSet 和 JDK String 中没有使用它?
编辑
最近的 Java 7 版本添加了自定义 String.hash32 实现,其中包含对这种特殊情况的处理:
// ensure result is not zero to avoid recalcing
h = (0 != h) ? h : 1;
【问题讨论】:
-
为“\0”之类的字符串重新计算哈希码的代价可能太小了,以至于不值得放入诸如“if (hash == 0) 之类的大学风格/人为的代码中) 哈希++;"
标签: java caching guava immutability hashcode