一尘不染

为什么String的hashCode()不缓存0?

java

我在Java 6的String源代码中注意到,hashCode仅缓存除0以外的值。以下代码段显示了性能差异:

public class Main{
   static void test(String s) {
      long start = System.currentTimeMillis();
      for (int i = 0; i < 10000000; i++) {
         s.hashCode();
      }
      System.out.format("Took %d ms.%n", System.currentTimeMillis() - start);
   }
   public static void main(String[] args) {
      String z = "Allocator redistricts; strict allocator redistricts strictly.";
      test(z);
      test(z.toUpperCase());
   }
}

在ideone.com中运行此命令可获得以下输出:

Took 1470 ms.
Took 58 ms.

所以我的问题是:

  • 为什么String的hashCode()不缓存0?
  • Java字符串哈希为0的概率是多少?
  • 避免对于每次哈希值都为0的字符串每次都重新计算哈希值的性能损失的最佳方法是什么?
  • 这是缓存值的最佳实践方法吗?(即除了一个缓存所有?)

为了您的娱乐,这里的每一行都是一个散列为0的字符串:

pollinating sandboxes
amusement & hemophilias
schoolworks = perversive
electrolysissweeteners.net
constitutionalunstableness.net
grinnerslaphappier.org
BLEACHINGFEMININELY.NET
WWW.BUMRACEGOERS.ORG
WWW.RACCOONPRUDENTIALS.NET
Microcomputers: the unredeemed lollipop...
Incentively, my dear, I don't tessellate a derangement.
A person who never yodelled an apology, never preened vocalizing transsexuals.

阅读 283

收藏
2020-09-08

共1个答案

一尘不染

您不用担心。这是考虑此问题的一种方法。

假设您有一个应用程序什么都不做,只是整年都在哈希字符串周围。假设它需要全部存储在内存中的一千个字符串,以循环方式在它们上反复调用hashCode(),经过一百万次,然后再获取一千个新字符串,然后再次执行。

并假设字符串的哈希码为零的可能性实际上远大于1/2 ^ 32。我敢肯定,这是 有点 更大的1/2 ^ 32,但让我们说这是比差很多,像1 / ^
16(平方根!现在这是一个差很多!)。

在这种情况下,与其他任何人相比,Oracle工程师在改进这些字符串的哈希码的缓存方式方面将受益更多。因此,您给他们写信并要求他们修复它。他们发挥了魔力,因此只要s.hashCode()为零,它就会
立即 返回(甚至是第一次!100%的改善!)。可以说,在任何其他情况下,他们这样做都不会降低性能。

万岁!现在您的应用程序…让我们看看…快0.0015%!

过去需要花费一整天的时间现在只需23小时,57分钟和48秒!

并且请记住,我们设置了场景以使怀疑的所有可能好处,通常到了可笑的程度。

这对您来说值得吗?

编辑:
自从几个小时前发布此消息以来,我让我的一个处理器疯狂运行以寻找具有零哈希码的两个单词的短语。到目前为止,它提出了:甲壳动物zorillo,计时码表schtoff,挫伤性的回廊状,creashaks的有机杂志,鼓木巨石头,可进行电分析的且难以理解的。这是在大约2
^
35的可能性中进行的,因此,理想的分布情况下,我们希望只能看到8。显然,到完成时,我们的数量将是原来的几倍,但不会更多。更重要的是,我现在提出了一些有趣的乐队名称/专辑名称!没有公平的偷窃!

2020-09-08