java - 为什么空 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
. 如果这个想法有缺陷(除了向后兼容性问题),请解释原因。
我发现了其他接近该问题的问题/答案......但没有一个确切的答案:
解决方案
为什么空 Java 字符串的哈希码为零?
简短的回答是因为它是在 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
可以用作 a 中的键,HashMap
或者LinkedHashMap
用作 a 的值HashSet
。但它不是ConcurrentHashMap
orHashTable
orTreeMap
or的情况TreeSet
。确实,我从应该知道的消息来源那里听说过:负责集合类型的 Java 设计者认为支持
null
键是错误的,并且这就是为什么
ConcurrentHashMap
不支持这一点的原因之一。
鉴于null
在应用程序中使用键(可以说)是被误导的,为键提供小幅改进的破坏性优化同样是被误导的。null
可以说,实际上并没有多少代码取决于String.hashCode
算法的指定细节。但问题是,我们或 Java 设计者都没有一个好的方法来量化有多少旧应用程序实际上会破坏1。
但是打破现有 Java 应用程序的 0.001% 仍然是大量的应用程序,以及很多恼火的 Oracle 客户。这足以让你的想法成为一个非首发......对于Java。
1 - 这将是应用程序程序员的错误,因为依赖哈希码值在某种程度上是“回溯实践”的论点并没有被我洗掉。在这种情况下(无论出于何种原因)指定算法的事实意味着程序员应该能够依赖它。
推荐阅读
- c - C - 替换 if 语句
- python-3.x - 为什么这个 Pandas set_table_styles 指令不起作用?
- javascript - 如果自动填充表单,如何更改元素?
- javascript - OTree MouseOver 函数 JavaScript“添加了鼠标悬停以激活未定义”
- arrays - 循环遍历数组以在 Vba 中创建工作表
- google-cloud-logging - 在存在与模式匹配的字段时过滤 Google Cloud 中的日志
- html5-video - 主视频之前的商业视频
- html - 如何将播放速度按钮添加到我的 html 音频播放器
- python - 组合两列时出错:ValueError: Columns must be the same lenght as key
- swiftui - SwiftUI 绑定到列表元素仅更新以正确顺序输入的值