V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
codewld
V2EX  ›  Java

不懂就问, LinkedHashSet 为什么要这样设计?

  •  
  •   codewld · 2023-01-28 17:28:21 +08:00 · 2026 次点击
    这是一个创建于 665 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 需要额外携带一部分不属于它的代码,实在不够优雅。

    11 条回复    2023-02-11 13:44:51 +08:00
    Origami404
        1
    Origami404  
       2023-01-28 17:47:47 +08:00 via Android
    说不定就是因为懒得再写一次代码呢,每个映射只需要多付出一个指针的大小就可以立得一个 set ,多快乐啊

    有些语言支持零大小类型,这种语言的 xxSet<T> 可以直接是 xxMap<T ,Void> ,毫无额外开销。我记得 Rust 标准库里的似乎就是这样实现的,但是我不确定了。
    TtTtTtT
        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
    xtreme1
        3
    xtreme1  
       2023-01-28 18:05:28 +08:00
    codewld
        4
    codewld  
    OP
       2023-01-28 18:05:35 +08:00
    @Origami404 除了开销,代码书写上也有问题。这个构造函数有且只有 LinkedHashSet 会用到,那为什么不直接把这些代码挪到 LinkedHashSet 里面呢?
    Bingchunmoli
        5
    Bingchunmoli  
       2023-01-28 18:07:47 +08:00 via Android
    @codewld 如果我拓展 hashset 这个是不是有可能用到
    codewld
        6
    codewld  
    OP
       2023-01-28 18:08:30 +08:00
    @TtTtTtT 我觉得"增加一个 map 的构造器"这个方案比现有的好得多
    codewld
        7
    codewld  
    OP
       2023-01-28 18:11:35 +08:00
    @Bingchunmoli 这个构造函数只和 LinkedHashSet 相关,假设代码已经挪出去,直接继承 LinkedHashSet 扩展就好了。
    Bingchunmoli
        8
    Bingchunmoli  
       2023-01-29 10:06:41 +08:00 via Android
    @codewld linked 是链表,我不用链表呢
    codewld
        9
    codewld  
    OP
       2023-01-29 12:05:41 +08:00
    @Bingchunmoli 这个问题正是现有设计无法解决的,不管用不用链表,HashSet 中都始终持有这一部分只属于链表的代码。
    Bingchunmoli
        10
    Bingchunmoli  
       2023-01-29 12:41:00 +08:00 via Android
    @codewld 😯,是的,看差了
    MineDog
        11
    MineDog  
       2023-02-11 13:44:51 +08:00
    @codewld #9 2 楼提了一下,可能就是为了保证内部 map 的私有性,毕竟这里是 HashSet ,它一般也只会用到 HashMap 作为内部实现,当然写成一个默认访问级别的 map 传参构造方法也行,只是人家选了现在的写法。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1008 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 23:10 · PVG 07:10 · LAX 15:10 · JFK 18:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.