当许多键具有相同的哈希码时,Java 8 的 HashMap 如何退化为平衡树?

2024-02-20

当许多键具有相同的哈希码时,Java 8 的 HashMap 如何退化为平衡树?我读到密钥应该实现Comparable定义排序。 HashMap如何结合散列和自然排序来实现树?没有实现的类怎么办Comparable,或者当多个、不可相互比较时Comparable实现是同一个映射中的键吗?


The 实施说明评论 http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/a006fa0a9e8f/src/share/classes/java/util/HashMap.java#l143HashMap 中对 HashMap 操作的描述比我自己写的更好。理解树节点及其排序的相关部分是:

该映射通常充当分箱(分桶)哈希表,但当分箱变得太大时,它们会转换为 TreeNode 的分箱,每个结构与 java.util.TreeMap 中的结构类似。 [...] TreeNodes 的 bin 可以像其他任何节点一样被遍历和使用,而且在填充过多时还支持更快的查找。 [...]

Tree bins(即,其元素都是 TreeNodes 的 bins)主要通过 hashCode 排序,但在关系的情况下,如果两个元素属于相同的“C 类实现 Comparable”类型,则使用它们的compareTo 方法进行排序。 (我们通过反射保守地检查泛型类型以验证这一点 - 请参阅方法可比类 http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/a006fa0a9e8f/src/share/classes/java/util/HashMap.java#l341)。当键具有不同的哈希值或可排序时,树箱的增加的复杂性在提供最坏情况的 O(log n) 操作方面是值得的,因此,在意外或恶意使用情况下,性能会适度下降,其中 hashCode() 方法返回的值很差分布式的,以及许多键共享 hashCode 的那些,只要它们也是可比较的。 (如果这些都不适用,与不采取预防措施相比,我们可能会在时间和空间上浪费大约两倍。但唯一已知的情况源于不良的用户编程实践,这些实践已经很慢,以至于几乎没有什么区别。)

当两个对象的哈希码相等但不能相互比较时,方法tieBreakOrder http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/a006fa0a9e8f/src/share/classes/java/util/HashMap.java#l1876被调用来打破平局,首先通过字符串比较getClass().getName()(!),然后通过比较System.identityHashCode.

实际的树构建开始于treeifyBin http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/a006fa0a9e8f/src/share/classes/java/util/HashMap.java#l750,当垃圾箱到达时开始TREEIFY_THRESHOLD http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/a006fa0a9e8f/src/share/classes/java/util/HashMap.java#l249(当前为 8),假设哈希表至少有MIN_TREEIFY_CAPACITY http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/a006fa0a9e8f/src/share/classes/java/util/HashMap.java#l266容量(当前 64)。这是一个最正常的红黑树实现(记入CLR http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/a006fa0a9e8f/src/share/classes/java/util/HashMap.java#l2168),但有一些复杂性需要以与散列箱相同的方式支持遍历(例如,removeTreeNode http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/a006fa0a9e8f/src/share/classes/java/util/HashMap.java#l2005).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当许多键具有相同的哈希码时,Java 8 的 HashMap 如何退化为平衡树? 的相关文章

随机推荐

  • 如何替换Python字符串中的占位符

    如果我在Python中有一个这样的字符串 我该如何填充占位符 s uri1 s file1 txt md5 s uri2 s file2 txt md5 s uri3 s file3 txt md5 s The uri然而 将保持不变 md
  • 为什么我无法使用 NodeJS 解密使用 openssl 加密的文件?

    我使用命令行加密了一个文件 openssl aes 256 cbc in tmp text txt out tmp text crypt 然后我尝试使用以下 JavaScript 代码对其进行解密 crypto require crypto
  • Rails 3 在所有表单上去除 before_validation 的空格

    我对 Rails 比较陌生 有点惊讶这不是一种可配置的行为 至少我还没有找到一个 我本以为 99 的表单都会受益于修剪所有表单中的空白string text领域 我猜我错了 无论如何 我正在寻找一种 DRY 方法来从 Rails 3 应用程
  • 使用 Seaborn 和 Matplotlib 对齐热图和线图的共享子图中的 x 轴刻度

    绘制一个热图和线图使用具有共享 x 轴的 Seaborn 热图的刻度被放置在热图条的中间 因此 底部线图将继承热图刻度位置和标签 而不反映真实数据 因为线图刻度应从零开始 换句话说 我需要将两个图的刻度移动到从 x 轴原点开始 最佳 或者将
  • 在子进程中使用信号

    我想创建一个简单的程序 它使用 fork 并创建一个子进程 该子进程使用暂停正在等待 我希望这个子进程在从父进程收到特定信号后启动 我写的代码 include
  • 从第三方网站 POST 后丢失会话数据

    我有一个 Laravel 网站 它重定向到支付提供商 外部第三方网站 当用户完成付款后 他们会通过 POST 请求重定向回我的网站 我遇到的问题是 当用户返回确认页面时 他们的会话会丢失 我想知道这是否是 PHP 的普遍行为 但它似乎是 L
  • Android Studio 3 中的“活动管理器状态”在哪里?

    Android studio 2 x 中有一个非常方便的调试功能 但目前 3 x 中没有 它有点隐藏在用户界面中 然后它会提示详细的活动管理器状态 我知道 我可以通过以下方式获取该输出adb shell dumpsys activity t
  • Google Data Studio:如何计算特定事件的数量

    我知道以前有人问过类似的问题 但我没有找到答案 例子在这里 https support google com datastudio thread 22779471 hl en 另一个例子 https stackoverflow com qu
  • 在 Ubuntu 16.04 上安装 Oracle Datamodeler

    我正在我的 Ubuntu 16 04 工作站上设置 Oracle 开发环境 安装 Oracle 12c 是一个挑战 但有几个非常有用的教程让我走上了正轨 下列的迪兹韦尔的 https www dizwell com wordpress te
  • 从 Outlook 获取收件箱

    我在 Outlook 2010 中配置了两个 Exchange 帐户 但是我无法找到如何访问第二个帐户的收件箱 Session GetDefaultFolder 总是返回第一个 甚至枚举 Session Accounts 找到正确的帐户并调
  • for 循环缺少初始化

    我见过 for and for s 0 s 怎么就这样空白了 谢谢 The for声明的工作原理如下 for initialization test condition update 这三个中的任何一个或全部都可以省略 留空 所以 for
  • Eclipse源代码下载[已关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 在新的 Eclipse 中 我们具有右键单击 XSD 并从中生成 XML 的功能 有人可以指导我在哪里可以获得 Eclipse 此功能的源代码吗 我猜
  • 如何动态更改按钮模板WPF

    我怎样才能改变一个Button模板动态 我有一个ComboBox通过更改他选择的值 我想更改Button Template 这就是我一直在努力做的事情
  • Reactjs - 在悬停时渲染从数组渲染的列表项的单个图标

    我有这种从对象数组渲染的卡片 父组件 foo bar baz name string path string state isHovering false handleMouseHover gt const isHovering this
  • 调用 new 和 getInstance() 之间的区别

    正在呼叫Class getInstance 相当于new Class 我知道后者调用了构造函数 但是呢getInstance 谢谢 没有这样的方法Class getInstance 你可能把它与Class newInstance http
  • 将一串数字转换为十六进制并返回十进制 pandas python

    我目前有一串值 是在过滤 csv 文件中的数据后检索到的 最终我必须对数据进行一些过滤 但我有与列表 数据帧或数组相同的数字 我只需要获取字符串中的数字并将它们转换为十六进制 然后获取十六进制的前 8 个数字并将其转换为字符串中每个元素的十
  • 如何在多个存储过程上使用事务?

    您能否在一个存储过程中启动一项事务 然后在嵌套过程中回滚或提交它 提交和回滚有不同的效果 COMMIT 递减 TRANCOUNT ROLLBACK 将其推回到零 发生这种情况是因为 SQL Server 并不真正支持嵌套事务 如果您在嵌套存
  • Angular 6 延迟加载路线

    我想在我的项目中为管理员添加延迟加载路由 我使用 ASP Net Core 后端和 Angular 6 前端 因此我的编译代码输出目录是 wwwRoot Angular dist 当我编译项目时 我看到那里存在文件 admin admin
  • 为什么文件范围静态变量必须为零初始化?

    C 默认初始化不会将具有自动存储的变量清零 为什么要对静态存储变量进行特殊处理 C 和 C 定义的东西必须兼容吗 如果是这种情况 为什么 C 决定进行零初始化 如果文件范围静态变量提供了初始化程序 它们将首先被零初始化 然后再次被常量 动态
  • 当许多键具有相同的哈希码时,Java 8 的 HashMap 如何退化为平衡树?

    当许多键具有相同的哈希码时 Java 8 的 HashMap 如何退化为平衡树 我读到密钥应该实现Comparable定义排序 HashMap如何结合散列和自然排序来实现树 没有实现的类怎么办Comparable 或者当多个 不可相互比较时