今天在排查反应问题的时分,注意到有一处逻辑将几个属性拼接成 String 再核算 hashCode 作为表的主键运用。明显这是一处关于 DB 数据索引的小优化( 对比传统复合主键写法来说 ),但理论上可能存在两个问题:

  • 数据项间存在主键核算结果哈希冲突的状况,会导致 DB 数据紊乱
  • String 的 hashCode 完成跨 ART 实例 / 系统版别不安稳,会导致 DB 数据无法被正确索引

具体实践上来说,在项目主工程中全局搜索了下,发现有多处相似的写法( 大约是呈现了历史代码人传人的状况 ),最早的提交记载能够追溯到 15 年下半年,且某些表重度用户应该会呈现上万条表记载的状况,基于此能够以为截止到当下,上述两个问题都不太可能会呈现。

哈希冲突的问题,理论上散布均匀的 hashCode 完成,大约超过 70k 条数据就会有 50% 的概率呈现,具体评论可参见 String.hashCode() is plenty unique。

至于 String.hashCode 完成的安稳性,是否有一个清晰的约好呢?

从系统版别跨 ART 实例来说( 即同一 ART 完成跨进程的状况 ),String.hashCode 的完成明显是安稳的。

从 String.hashCode 的文档上也能够看出来:

Android 上 String.hashCode 的实现稳定吗?
注意到文档上乃至直接规则了 String.hashCode 的算法,实践也就是 Android Studio 默许帮咱们补全 hashCode 完成的那一种。

从跨 Android 系统版别来说,String.hashCode 的完成是否是保证安稳的呢?

前面说到 String 的接口文档上是直接规则了 hashCode 的算法的,但接口文档本身理论上也能够跟着版别的改变而改变,是否有这么一个地方清晰界说了 String.hashCode 的跨版别兼容性呢?

于是我问了下 chatGPT,它的答案是 Java 语言标准中清晰规则了 String 的 hashCode 算法,给出的引用是这样的:

Android 上 String.hashCode 的实现稳定吗?
似乎很有道理,我顺着链接 jls-17.5.3 找了下 JLS 的内容,发现引用的章节实践既不是讲 String 也不是讲 hashCode 的,没关系,前后几个版别的 JLS 也全局搜索下 hash,结果也没有相关内容,果然 chatGPT 又是在一本正经地逗我…

只能自给自足 Google 了,翻到了一个上古时代 JDK 的 bug 记载 java.lang.String.hashCode spec incorrectly describes the hash algorithm,里边说到了最早的 JLS 上的确描绘了 String.hashCode 的算法,但完成却和标准不符,这个问题在 JDK 1.2 上被修正,同时 JLS 的描绘应该被相应地更新( 看来 chatGPT 虽然骗了我,但又没有完全骗 )。不过 SE1.2 对应的 JLS 文档简单找了下没找到,而 SE6 对应的 JLS 文档上就的确没有 String.hashCode 的相关描绘了。这里能够看到至少在上古时代的 JDK 完成上,String.hashCode 的确是存在有完成不一致的状况的,不过这跟 Android 是没啥关系了。

发现 Stack Overflow 很多年前也就有过相似的提问: Consistency of hashCode() on a Java string,从评论内容看,普遍的共识是从向后兼容考虑,大约率 JDK 的完成也不会修改这个长久以来都很安稳的 String.hashCode 算法了。

Android 上 String.hashCode 的完成安稳吗?大约它是安稳的。不过关于相似需要核算 hashCode 再耐久化存储的场景,我挑选直接让 IDE 帮我生成一个绝对安稳的 hashCode 完成 。