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对内部双向链表的遍历顺序为插入顺序




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

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

相关文章
|
Java
Java 对象间关系(依赖、关联、聚合和组合)
面向对象设计 对象间关系:依赖、关联、聚合和组合,四种关系容易混淆。特别后三种,只是在语义上有所区别,所谓语义就是指上下文环境、特定情景等。 
1376 1
Collection接口详解
Collection接口详解
|
SQL Java 数据库连接
|
存储 缓存 Java
滚雪球学Java(64):LinkedHashSet原理及实现解析
【6月更文挑战第18天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
228 1
滚雪球学Java(64):LinkedHashSet原理及实现解析
|
10月前
|
传感器 安全 物联网
时序数据库TDengine + MQTT :车联网时序数据库如何高效接入
现代新能源汽车配备大量传感器,产生海量数据需上报至车联网平台。TDengine作为时序大数据平台,支持MQTT协议,可轻松实现车辆状态、位置及用户行为数据的实时采集与分析,提升驾驶体验和安全保障。通过简单的Web界面配置,无需编写代码,即可完成从MQTT到TDengine的数据接入。整个过程包括注册TDengine Cloud、创建数据库、安装代理插件、新增数据源、配置解析规则等步骤,快速实现数据同步。
357 2
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
1320 24
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
256 4
|
缓存 负载均衡 应用服务中间件
Nginx入门 -- Nginx 配置详解
Nginx入门 -- Nginx 配置详解
1060 0
|
存储 安全 测试技术
基于SpringBoot+Vue健身房管理系统的设计与实现(源码+部署说明+演示视频+源码介绍)(2)
基于SpringBoot+Vue健身房管理系统的设计与实现(源码+部署说明+演示视频+源码介绍)
994 1
|
缓存 算法 Java
认真学习Java集合之LinkedHashMap的实现原理
认真学习Java集合之LinkedHashMap的实现原理
312 0
认真学习Java集合之LinkedHashMap的实现原理