首页 > 解决方案 > 为什么空 Java 字符串的哈希码为零?

问题描述

直到最近,我才发现空String的哈希码为零。这让我感到惊讶,因为null通常分配的哈希码为零,例如,Objects.hashCode(Object)ArrayList.hashCode()

以下是 JDK 11源代码String.hashCode()

/** Cache the hash code for the string */
private int hash; // Default to 0

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        hash = h = isLatin1() ? StringLatin1.hashCode(value)
                              : StringUTF16.hashCode(value);
    }
    return h;
}

想法:一个空的String可能有哈希码一,因为这将匹配Arrays.hashCode(Object[])空数组。或者,可以使用任何其他硬编码的非零值,类似于serialVersionUID. 目的是区别于null. 如果这个想法有缺陷(除了向后兼容性问题),请解释原因。

我发现了其他接近该问题的问题/答案......但没有一个确切的答案:

标签: javahashcode

解决方案


为什么空 Java 字符串的哈希码为零?

简短的回答是因为它是在 Java 1.2 中指定的方式。(Java 1.2 规范可能与早期 Java 版本中的实现相匹配。)

我想不出String.hashcode("") 应该为零的强有力的技术原因。

但是,我不同意你的论点,因为它String.hashCode("")应该是非零的,因为Objects.hashCode(null)它是零。

  1. 该类Objects是在 Java 7 中添加的。同样,Arrays.hashCode方法是在 Java 1.5 中添加的。因此,如果有的话,那ObjectsArrays不正确的。

  2. 定义中没有期望hashCode()任何特定的不同值对应该是不同的。充其量更改 hashCode 值""将是一个的优化。请注意,这String.equals(null)是通过instanceof测试有效处理的。

  3. 哈希表在同一个表中同时具有null""作为键是不常见的。事实上,我什至会说,这很可能表明您需要null和提供条目的设计或实现缺陷""

  4. 可以说,null根本不应该将其作为密钥来支持Map。我知道它null可以用作 a 中的键,HashMap或者LinkedHashMap用作 a 的值HashSet。但它不是ConcurrentHashMapor HashTableor TreeMapor的情况TreeSet。确实,我从应该知道的消息来源那里听说过:

    • 负责集合类型的 Java 设计者认为支持null键是错误的,并且

    • 这就是为什么ConcurrentHashMap不支持这一点的原因之一。

鉴于null在应用程序中使用键(可以说)是被误导的,为键提供小幅改进的破坏性优化同样是被误导的。null

可以说,实际上并没有多少代码取决于String.hashCode算法的指定细节。但问题是,我们或 Java 设计者都没有一个好的方法来量化有多少旧应用程序实际上会破坏1

但是打破现有 Java 应用程序的 0.001% 仍然是大量的应用程序,以及很多恼火的 Oracle 客户。这足以让你的想法成为一个非首发......对于Java。


1 - 这将是应用程序程序员的错误,因为依赖哈希码值在某种程度上是“回溯实践”的论点并没有被我洗掉。在这种情况下(无论出于何种原因)指定算法的事实意味着程序员应该能够依赖它。


推荐阅读