哈希表的键类型K不需要实现Comparable接口?
来源:1-5 实现属于我们自己的哈希表
DBP3
2023-03-24 11:54:49
老师好,在实现哈希表的过程中,您说键的类型K不需要实现Comparable接口。但是,哈希表数组里的每个元素的类型是TreeMap,TreeMap是由红黑树实现,红黑树不就是要求键的类型K实现Comparable接口吗? 那为什么哈希表的键类型可以不用实现Comparable接口呢?
2回答
liuyubobobo
2023-03-28
我有点儿忘了我在这个课程中是如何解释这个问题的了,但是:
1)这个课程并不是一个 Java 的源码分析课程,所以我并没有深入分析 Java 的源码;
2)非常重要的,Java 的这个对哈希表的实现上的“优化”(在一定阈值吧哈希表的 bin 的存储结构从链表转换成树),并非是哈希表的标准实现方式。实际上除了 Java 语言之外,我还没有听说过其他语言的哈希表的底层实现是这样的。这是有原因的。我在这里简述了一下这个问题:https://class.imooc.com/course/qadetail/343152 ;在这里我更多的阐述了一下:https://t.zsxq.com/0cY7oLvEQ
所以,我相信我其实并没有在课程中对这个问题过于“较真”。
==========
但如果严谨的回答这个问题:
一个简单的理解是:如果你传入的 key 不可比较的话,就不会转化为树。
但实际上,因为 Java 中的所有的类都有 hashcode 函数,所以,所有的类一定可以通过 hashcode 作比较(只不过作比较的方式不是你所希望的或者你所定义的比较方式而已。Java 默认的 hashcode 的实现是基于对象所在的内存地址做编码。)所以,对于不可比较的 key,依然可以根据这个 key 的 hashcode 转换为红黑树。
但是,非常重要的一点是,在这种情况下,即便转换为了树,并不能带来性能的提升。这篇文章非常好地解释了这件事:https://yermilov.github.io/blog/2017/02/24/tiebreaker-regarding-java-hashmap-treenode-and-tiebreakorder/ (甚至因为存在转换过程,实际上拖慢了性能。)
因此,在这种情况下,你理解成 key 不可比较,就不转换,是没有问题的。(但实际上是转换了。)
如果你的问题是,传给 HashMap 的 Key 的类型没有被 Comparable 接口约束,怎么判断这个 key 是不是可以比较?这是一个技术细节了。
以 OpenJDK 的实现为例,1949 和 1950 行在做这个判断:https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.base/share/classes/java/util/HashMap.java
继续加油!:)
DBP3
提问者
2023-03-24
我明白了,老师在后续的课程里对此有解释。
相似问题