V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
codewld
V2EX  ›  Java

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

  •  
  •   codewld · Jan 28, 2023 · 2854 views
    This topic created in 1185 days ago, the information mentioned may be changed or developed.

    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 replies    2023-02-11 13:44:51 +08:00
    Origami404
        1
    Origami404  
       Jan 28, 2023 via Android
    说不定就是因为懒得再写一次代码呢,每个映射只需要多付出一个指针的大小就可以立得一个 set ,多快乐啊

    有些语言支持零大小类型,这种语言的 xxSet<T> 可以直接是 xxMap<T ,Void> ,毫无额外开销。我记得 Rust 标准库里的似乎就是这样实现的,但是我不确定了。
    TtTtTtT
        2
    TtTtTtT  
       Jan 28, 2023
    HashSet 本身也没有多少逻辑,本质上就是用 HashMap 实现 Set 。
    因此,基于继承的方案下,这里应该就是为了保护了 map 的 private ,然后开个 package private 的 constructor 给 LinkedHashSet 。

    也有其他几种方案能达到这个效果,比如开个 package private 的 constructor 传一个 map factory 之类的,或者把 map 变成 package private 的。但是都挺奇怪的。

    如果一定要说是根本问题是啥,就怪到 JVM 的单继承上,hhh
    codewld
        4
    codewld  
    OP
       Jan 28, 2023
    @Origami404 除了开销,代码书写上也有问题。这个构造函数有且只有 LinkedHashSet 会用到,那为什么不直接把这些代码挪到 LinkedHashSet 里面呢?
    Bingchunmoli
        5
    Bingchunmoli  
       Jan 28, 2023 via Android
    @codewld 如果我拓展 hashset 这个是不是有可能用到
    codewld
        6
    codewld  
    OP
       Jan 28, 2023
    @TtTtTtT 我觉得"增加一个 map 的构造器"这个方案比现有的好得多
    codewld
        7
    codewld  
    OP
       Jan 28, 2023
    @Bingchunmoli 这个构造函数只和 LinkedHashSet 相关,假设代码已经挪出去,直接继承 LinkedHashSet 扩展就好了。
    Bingchunmoli
        8
    Bingchunmoli  
       Jan 29, 2023 via Android
    @codewld linked 是链表,我不用链表呢
    codewld
        9
    codewld  
    OP
       Jan 29, 2023
    @Bingchunmoli 这个问题正是现有设计无法解决的,不管用不用链表,HashSet 中都始终持有这一部分只属于链表的代码。
    Bingchunmoli
        10
    Bingchunmoli  
       Jan 29, 2023 via Android
    @codewld 😯,是的,看差了
    MineDog
        11
    MineDog  
       Feb 11, 2023
    @codewld #9 2 楼提了一下,可能就是为了保证内部 map 的私有性,毕竟这里是 HashSet ,它一般也只会用到 HashMap 作为内部实现,当然写成一个默认访问级别的 map 传参构造方法也行,只是人家选了现在的写法。。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3564 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 52ms · UTC 11:54 · PVG 19:54 · LAX 04:54 · JFK 07:54
    ♥ Do have faith in what you're doing.