为什么一个空的java字符串的哈希码为零?

t5zmwmid  于 2021-06-30  发布在  Java
关注(0)|答案(2)|浏览(734)

直到最近,我才发现 String 哈希代码为零。我很惊讶因为 null 通常分配哈希码为零,例如。, Objects.hashCode(Object) 以及 ArrayList.hashCode() .
以下是JDK11的源代码 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 可能有散列码1,因为那会匹配 Arrays.hashCode(Object[]) 对于空数组。或者,可以使用任何其他硬编码的非零值,类似于 serialVersionUID . 目的是区别于 null . 如果这个想法有缺陷(除了向后兼容性问题),请解释原因。
我发现其他问题/答案接近这个问题。。。但没有人确切回答:
非空字符串的哈希码是否为零?
为什么string的hashcode()不能缓存0?
https://stackoverflow.com/a/64082954/257299

camsedfj

camsedfj1#

为什么空java字符串的哈希代码为零?
简单的回答是因为它是在Java1.2中被指定的(Java1.2规范可能与早期java版本中的实现相匹配。)
我想不出一个强有力的技术原因 String.hashcode("") 应该是零。
但是,我不同意你的论点 String.hashCode("") 应为非零,因为 Objects.hashCode(null) 是零。
这个 Objects 类是在Java7中添加的。同样地 Arrays.hashCode 方法是在Java1.5中添加的。所以如果有什么的话,那就是 Objects 以及 Arrays 这是不正确的。
世界上没有期望 hashCode() 任何特定的不同值对应该是不同的定义。最多更改 "" 会是一个小的优化。请注意 String.equals(null) 通过 instanceof 测试。
哈希表两者兼有是不寻常的 null 以及 "" 作为同一表中的键。事实上,我甚至可以说,它很可能表示一个设计或实现缺陷,您需要为这两个缺陷都添加条目 null 以及 "" .
可以说 null 不应作为 Map 一点都不重要。我知道 null 可以用作 HashMap 或者 LinkedHashMap ,或作为 HashSet . 但事实并非如此 ConcurrentHashMap 或者 HashTable 或者 TreeMap 或者 TreeSet . 事实上,我从应该知道的人那里听说:
负责集合类型的java设计者认为支持这些类型是一个错误 null 钥匙,和
这就是为什么 ConcurrentHashMap 不支持这个。
鉴于 null 应用程序中的键(可以说)被误导了,这是一种突破性的优化,可以为 null 钥匙也同样被误导了。
可以说,实际上没有多少代码依赖于 String.hashCode 算法。但问题是,无论是我们还是java设计者都没有一个好的方法来量化有多少旧的应用程序会真正崩溃。
但是,现有java应用程序中只有0.001%的应用程序被破坏,这仍然是一个很大的应用程序问题,也是很多令oracle客户恼火的问题。这足以让你的想法成为一个不起眼的想法。。。对于java。
1-那种认为依赖hashcode值是应用程序程序员的错的观点不知何故是“反向实践”,我不理解。在这种情况下(无论出于什么原因)指定了算法这一事实意味着程序员应该能够依赖它。

rmbxnbpk

rmbxnbpk2#

这个 hashCode() 最初的目的是 This method is supported for the benefit of hash tables such as those provided by HashMap. 因此这意味着hashcode的实际值除了可能的相似性之外没有任何意义,正如doc所说: It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. 关于任意值 0 对于空字符串和空字符串,字符串哈希代码的计算方式会导致其他可能的错误 0 hashcode甚至用于非空字符串。

System.out.println("".hashCode());             // >> 0
System.out.println("\0".hashCode());           // >> 0
System.out.println("\u0000".hashCode());       // >> 0
System.out.println("\u0000\u0000".hashCode()); // >> 0
System.out.println("\0\0\0".hashCode());       // >> 0

所以 0 空字符串的值是有意义的,因为计算是

int h = 0;
for (byte v : value) {
    h = 31 * h + (v & 0xff);
}
return h;

所以即使是捷径 if (h == 0 && value.length > 0) 如果没有使用,仍然会导致 0 ,这只是一条优化路径。
在某种程度上,人们可以说 null 哈希代码不应为空 0 但也许是这样的 -1 . 但是,既然hashcode没有也不应该带有任何意义,那么它无论如何也不重要。

相关问题