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

标签 java hashmap java-8

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

最佳答案

implementation notes comment in HashMap 比我自己写的更好地描述了 HashMap 的操作。了解树节点及其排序的相关部分是:

This map usually acts as a binned (bucketed) hash table, but when bins get too large, they are transformed into bins of TreeNodes, each structured similarly to those in java.util.TreeMap. [...] Bins of TreeNodes may be traversed and used like any others, but additionally support faster lookup when overpopulated. [...]

Tree bins (i.e., bins whose elements are all TreeNodes) are ordered primarily by hashCode, but in the case of ties, if two elements are of the same "class C implements Comparable" type then their compareTo method is used for ordering. (We conservatively check generic types via reflection to validate this -- see method comparableClassFor). The added complexity of tree bins is worthwhile in providing worst-case O(log n) operations when keys either have distinct hashes or are orderable, Thus, performance degrades gracefully under accidental or malicious usages in which hashCode() methods return values that are poorly distributed, as well as those in which many keys share a hashCode, so long as they are also Comparable. (If neither of these apply, we may waste about a factor of two in time and space compared to taking no precautions. But the only known cases stem from poor user programming practices that are already so slow that this makes little difference.)

当两个对象具有相同的哈希码但不能相互比较时,方法tieBreakOrder被调用以打破平局,首先通过 getClass().getName() (!) 上的字符串比较,然后通过比较 System.identityHashCode

实际的树构建开始于 treeifyBin , 从 bin 到达 TREEIFY_THRESHOLD 时开始(目前为 8 个),假设哈希表至少有 MIN_TREEIFY_CAPACITY容量(目前为 64)。这是一个最普通的红黑树实现( crediting CLR ),支持以与哈希箱相同的方式遍历的一些复杂性(例如,removeTreeNode )。

关于java - 当许多键具有相同的哈希码时,Java 8 的 HashMap 如何退化为平衡树?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30164087/

相关文章:

java - GC 不清除范围内的对象

java - 如何正确格式化 Hibernate 实体以与 ember-data 一起使用?

java - 坚持这段代码

java - 使用 javax 和 pdfbox 的静默打印机应用程序

Java - 在对象的ArrayList中搜索字符串

java - 将两个List<>映射到HashMap

java - 使用接口(interface) Class<T> 作为键来获取具体的实例值?

java - OpenJDK 项目的有效 RSS 更改在哪里?

java - 使用谓词验证搜索参数

javascript - JavaScript 在内部如何迭代对象键?