LinkedHashSet 源码可以精简如下:
public class LinkedHashSet<E> extends HashSet<E> { public inkedHashSet() { super(16, .75f, true); } }
其中,super 关键字调用的是父类中 "only used by LinkedHashSet" 的构造函数,如下:
public class HashSet<E> { /** * Constructs a new, empty linked hash set. (This package private * constructor is only used by LinkedHashSet.) The backing * HashMap instance is a LinkedHashMap with the specified initial * capacity and the specified load factor. */ HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); } }
在这样的设计下,HashSet 需要额外携带一部分不属于它的代码,实在不够优雅。
![]() | 1 Origami404 2023-01-28 17:47:47 +08:00 via Android 说不定就是因为懒得再写一次代码呢,每个映射只需要多付出一个指针的大小就可以立得一个 set ,多快乐啊 有些语言支持零大小类型,这种语言的 xxSet<T> 可以直接是 xxMap<T ,Void> ,毫无额外开销。我记得 Rust 标准库里的似乎就是这样实现的,但是我不确定了。 |
2 TtTtTtT 2023-01-28 18:04:06 +08:00 HashSet 本身也没有多少逻辑,本质上就是用 HashMap 实现 Set 。 因此,基于继承的方案下,这里应该就是为了保护了 map 的 private ,然后开个 package private 的 constructor 给 LinkedHashSet 。 也有其他几种方案能达到这个效果,比如开个 package private 的 constructor 传一个 map factory 之类的,或者把 map 变成 package private 的。但是都挺奇怪的。 如果一定要说是根本问题是啥,就怪到 JVM 的单继承上,hhh |
![]() | 3 xtreme1 2023-01-28 18:05:28 +08:00 |
![]() | 4 codewld OP @Origami404 除了开销,代码书写上也有问题。这个构造函数有且只有 LinkedHashSet 会用到,那为什么不直接把这些代码挪到 LinkedHashSet 里面呢? |
5 Bingchunmoli 2023-01-28 18:07:47 +08:00 via Android @codewld 如果我拓展 hashset 这个是不是有可能用到 |
![]() | 7 codewld OP @Bingchunmoli 这个构造函数只和 LinkedHashSet 相关,假设代码已经挪出去,直接继承 LinkedHashSet 扩展就好了。 |
8 Bingchunmoli 2023-01-29 10:06:41 +08:00 via Android @codewld linked 是链表,我不用链表呢 |
![]() | 9 codewld OP @Bingchunmoli 这个问题正是现有设计无法解决的,不管用不用链表,HashSet 中都始终持有这一部分只属于链表的代码。 |
10 Bingchunmoli 2023-01-29 12:41:00 +08:00 via Android @codewld ,是的,看差了 |