LinkedHashSet源码详解

简介: LinkedHashSet源码详解

一、介绍

前面文章中我们从源码详细介绍了继承于HashMap的LinkedHashMap,并通过图片示例讲解了LinkedHashMap是如何在HashMap的哈希表上将各个节点通过双向链表串起来的。

也讲解了基于HashMap实现的HashSet,那么是否存在类似于LinkedHashMap原理的一种Set集合?答案是肯定的,而且是我们本篇文章要讲的LinkedHashSet

顾名思义,LinkedHashSet是基于LinkedHashMap实现的一个Set集合。

另外,本片文章虽然不长,但是对前置知识点有着很强的依赖,需要掌握的前置知识有:HashMap(必选)红黑树(可选)LinkedHashMap(必选)HashSet(必选)

二、类的声明

public class LinkedHashSet<E> extends HashSet<E>
                                implements Set<E>, Cloneable, java.io.Serializable

从类的声明中可以看到

  • 继承HashSet,表示LinkedHashSet是对HashSet的扩展。
  • 实现set接口,满足Set集合的定义
  • 实现了Cloneable接口,提供了对象克隆方法,但请注意,是浅克隆
  • 实现了Serializable接口,支持序列化

三、构造方法

前面我们在讲HashSet的构造方法时,其中有一个构造方法我们做了特殊对待,如下所示

HashSet(int initialCapacity, float loadFactor, boolean dummy) {
   
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

该构造方法创建的map对象的类型是LinkedHashMap,不同于其他构造方法创建的HashMap对象。

而且我们有个关键点不要忽略,在LinkedHashMap中,双向链表的遍历顺序通过构造方法指定,如果没有指定,则使用默认顺序为插入顺序,即accessOrder=false。因此,上面的构造方法所创建的LinkedHashMap对象的双向链表遍历顺序为插入顺序

且该构造方法就是为了给其子类LinkedHashSet使用的。我们往下看

  • 无参构造

    创建LinkedHashMap实例为内部属性,并指定底层哈希表的初始容量为16,加载因子为0.75

    public LinkedHashSet() {
         
        super(16, .75f, true);
    }
    
  • 指定初始容量

    创建LinkedHashMap实例为内部属性,并指定底层哈希表的初始容量为initialCapacity,加载因子为0.75

    public LinkedHashSet(int initialCapacity) {
         
        super(initialCapacity, .75f, true);
    }
    
  • 指定初始容量和加载因子

    创建LinkedHashMap实例为内部属性,并指定底层哈希表的初始容量为initialCapacity,加载因子为loadFactor

    public LinkedHashSet(int initialCapacity, float loadFactor) {
         
        super(initialCapacity, loadFactor, true);
    }
    
  • 通过集合构造

    虽然说LinkedHashSet的底层是LinkedHashMap,但终究还是哈希表+双向链表,需要对哈希表的容量进行计算以避免频繁的扩容。

    创建LinkedHashMap实例作为内部对象后,通过addAll()方法将集合中的元素逐一保存,addAll()方法作为一个批量保存模版由其父类AbstractCollection提供,其中的add()方法由父类HashSet实现,这是设计模式—模版方法的体现。

    public LinkedHashSet(Collection<? extends E> c) {
         
        super(Math.max(2*c.size(), 11), .75f, true);
        addAll(c);
    }
    
    public boolean addAll(Collection<? extends E> c) {
         
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }
    

四、最后

看了LinkedHashSet的源码后,发现它只提供了以上几个构造函数,却没有提供各个方法。这是因为它继承于HashSet,因此HashSet中提供的方法都是可以被LinkedHashSet对象调用的,如add()、remove()、contains()等方法。所以不再过多介绍,

五、结论

  • LinkedHashSet内部维护一个LinkedHashMap对象,其底层数据结构为哈希表+链表+红黑树+双向链表
  • LinkedHashSet对内部双向链表的遍历顺序为插入顺序




纸上得来终觉浅,绝知此事要躬行。

————————————————我是万万岁,我们下期再见————————————————

相关文章
|
6月前
|
Java uml
|
6月前
|
存储 Java uml
|
5月前
|
安全
HashSet(源码解读)
HashSet(源码解读)
20 0
|
6月前
HashSet 源码解读
HashSet 源码解读
30 1
|
6月前
|
设计模式 存储 缓存
LinkedHashMap源码学习
LinkedHashMap源码学习
LinkedHashMap源码学习
|
6月前
|
存储 设计模式 Java
|
存储 对象存储 索引
HashSet 、LinkedHashSet 源码级详解
HashSet 、LinkedHashSet 源码级详解
66 0
|
缓存 Java 程序员
|
存储 缓存
LinkedHashMap源码简读
1、LinkedHashMap继承自HashMap,HashMap具有的特性它都具有。 2、实际上,LinkedHashMap是通过双向链表和散列表这两种数据组合实现的。LinkedHashMap中的“Linked”实际上指的是双向链表,并非指“用链表法解决散列冲突”。 3、LinkedHashMap不仅支持按照插入顺序遍历数据,还支持按照访问顺序来遍历数据。通过设置`accessOrder`属性为true即可。也就是说它本身就是一个支持LRU缓存淘汰策略的缓存系统。
|
算法 Java 程序员