直到最近,我才发现一个空的 String
哈希码为零。这让我感到惊讶,因为 null
通常分配的哈希码为零,例如,Objects.hashCode(Object)
和 ArrayList.hashCode()
.
这是 JDK 11 source code为 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
.如果这个想法有缺陷(除了向后兼容性问题),请解释原因。我发现了其他接近该问题的问题/答案......但没有一个确切的答案:
最佳答案
Why does an empty Java String have hash code zero?
简短的回答是因为它是在 Java 1.2 中指定的方式。 (Java 1.2 规范可能与早期 Java 版本中的实现相匹配。)
我想不出
String.hashcode("")
的强大技术原因应该为零。但是,我不同意您的观点
String.hashCode("")
应该是非零的,因为 Objects.hashCode(null)
为零。Objects
类是在 Java 7 中添加的。同样的 Arrays.hashCode
方法是在 Java 1.5 中添加的。所以如果有的话,它是 Objects
和 Arrays
这里是不正确的。hashCode()
中没有任何期待定义任何特定的不同值对应该是不同的。充其量更改 ""
的 hashCode 值将是一个小的优化。请注意 String.equals(null)
通过 instanceof
有效处理测试。null
是不寻常的。和 ""
作为同一个表中的键。事实上,我什至会说这很可能表明存在设计或实现缺陷,您需要为 null
提供条目。和 ""
.null
不应该被支持为 Map
关键。我知道null
可以用作 HashMap
中的 key 或 LinkedHashMap
,或作为 HashSet
的值.但对于 ConcurrentHashMap
而言,情况并非如此。或 HashTable
或 TreeMap
或 TreeSet
.事实上,我从应该知道的消息来源那里听说:null
key ,和ConcurrentHashMap
不支持这个。鉴于使用
null
应用程序中的键(可以说)被误导了,这是一个突破性的优化,为 null
提供了一个小的改进。键同样被误导。可以说实际上并没有多少代码依赖于
String.hashCode
的指定细节。算法。但问题是,无论是我们还是 Java 设计者,都没有一个很好的方法来量化实际上有多少旧应用程序会崩溃1。但是打破现有 Java 应用程序的 0.001% 仍然是很多应用程序,并且惹恼了很多 Oracle 客户。这足以使您的想法成为一个非初学者……对于 Java。
1 - 因为依赖哈希码值是应用程序程序员的错的论点在某种程度上是“反向练习”,这对我来说并不适用。在这种情况下指定算法的事实(无论出于何种原因)意味着程序员应该能够依赖它。
关于java - 为什么空的 Java 字符串的哈希码为零?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65275756/