LinkedHashSet 源码可以精简如下:
public class LinkedHashSet<E> extends HashSet<E> {
public LinkedHashSet() {
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 😯,是的,看差了
|