史上最全的Java容器集合之HashSet(源码解读)

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 前言文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820…种一棵树最好的时间是十年前,其次是现在

前言


文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820…

种一棵树最好的时间是十年前,其次是现在

絮叨


今天讲Set,List,Map已经讲完了,Set有时候我们也会用,去重,但是Stream流也有去重的方法所以现在也是用的少了,我这边打算就讲一个HashSet,有机会把函数式编程Stream写一下,巩固一下 哈哈。

🔥史上最全的Java容器集合之入门

🔥史上最全的Java容器集合之基础数据结构(手撕链表)

🔥史上最全的Java容器集合之ArrayList(源码解读)

🔥史上最全的Java容器集合之Vector和LinkedList(源码解读)

🔥史上最全的Java容器集合之equals 和 hashCode

🔥史上最全的Java容器集合之HashMap(源码解读)

🔥史上最全的Java容器集合之ConcurrentHashMap(源码解读)

🔥史上最全的Java容器集合之LinkedHashMap(源码解读)


HashSet概述


HashSet的代码行数 300多行,是我见过最少代码的集合了,非常简单,它有以下的特点

  • 没有重复元素的集合。底层基于HashMap来实现。
  • 非线程安全,创建线程安全的HashMap可以使用Collections.synchronizedSet。

HashSet源码解读


继承关系


  • 继承AbstractSet抽象类,实现Set接口
  • 实现java.io.Serialization接口,支持序列化
  • 实现Cloneable接口,支持对象克隆,浅复制


属性

//使用HashMap来保存HashSet的元素
    private transient HashMap<E,Object> map;
    //HashSet只使用到key,因此使用一个静态常量来充当HashSet的value值
    private static final Object PRESENT = new Object();
复制代码


构造方法

//使用默认容量大小16以及加载因子0.75初始化HashMap,构造HashSet
    public HashSet() {
        map = new HashMap<>();
    }
    //初始化指定集合和默认加载因子0.75的map,构造HashSet
    public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }
    //使用指定容量大小和加载因子初始化map,构造HashSet
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
    }
    //使用指定容量大小和默认加载因子0.75初始化map,构造HashSet
    public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }
    //包访问权限,构造空的LinkedHashSet
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
复制代码


方法

  • size()方法:内部调用Map的size方法。
public int size() {
        return map.size();
    }
复制代码


  • isEmpty()方法,也是调用map,里面是通过判断size是否为0来判断是否为null
public boolean isEmpty() {
        return map.isEmpty();
    }
复制代码


  • add()方法

HashSet的add方法内部通过HashMap.put()方法来实现key的添加,在HashMap内部真正执行的是putVal()方法,putVal这边就不说了 HashMap讲过

public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
复制代码


总结


HashSet 还真没啥讲了 ,就是把HashMap的key 拿来当数据存,基本上都是调用的是HashMap的方法,所以说讲的也少,总结一下吧

  • HashSet的实现支持null的key,同时HashSet的内部不支持重复的key
  • 不重复
  • 线程不安全

彩蛋


因为篇幅实在是太少了,TreeSet的底层是TreeMap,红黑树,这个知识点,我先欠着哈哈,所以也不算讲了。也就意味着Java容器要完结了,至少我们把大多数常用的容器过了一遍了,就算是面试也不至于说一问三不知了。

我们知道 ArrayList LinkedList HashMap HashSet 都是线程不安全的,但是有一个类可以让他们变的线程安全,它就是 Collections

  • Collections.synchronizedList
  • Collections.synchronizedMap
  • Collections.synchronizedSet

这个彩蛋就是我们来解密一下这个方法,挑选其中一个来讲


Collections.synchronizedList(List list) 方法源码

正常情况下,Collections.synchronizedList(List list) 返回的是一个 SynchronizedList 的对象,这个对象以组合的方式将对 List 的接口方法操作,委托给传入的 list 对象,并且对所有的接口方法对象加锁,得到并发安全性。

public static <T> List<T> synchronizedList(List<T> list) {
        return (list instanceof RandomAccess ?
                new SynchronizedRandomAccessList<>(list) :
                new SynchronizedList<>(list));
}
复制代码


我们可以看出,他其实就是new 了一个SynchronizedList ,那这个类又是何方神圣呢,继续看

static class SynchronizedList<E>
        extends SynchronizedCollection<E>
        implements List<E> {
        ...
        ...
        final List<E> list;
        SynchronizedList(List<E> list) {
            super(list);
            this.list = list;
        }
        SynchronizedList(List<E> list, Object mutex) {
            super(list, mutex);
            this.list = list;
        }
        ...
        ...
        public E get(int index) {
            synchronized (mutex) {return list.get(index);}
        }
        public E set(int index, E element) {
            synchronized (mutex) {return list.set(index, element);}
        }
        public void add(int index, E element) {
            synchronized (mutex) {list.add(index, element);}
        }
        public E remove(int index) {
            synchronized (mutex) {return list.remove(index);}
        }
    ...
    ...   
 }
复制代码


可以看到,SynchronizedList 的实现里,get, set, add 等操作都加了 mutex 对象锁,再将操作委托给最初传入的 list。 这就是以组合的方式,将非线程安全的对象,封装成线程安全对象,而实际的操作都是在原非线程安全对象上进行,只是在操作前给加了同步锁。

由于有很多业务场景下都有这种需求,所以 Java 类库中封装了这个工具类,给需要的模块使用。


但是值得一提的是,要是论Map的安全集合,还是ConcurrentHashMap效率比较高点,毕竟对象锁的粒度也是比较粗了。


版本说明

这里的源码是JDK8版本,不同版本可能会有所差异,但是基本原理都是一样的。

结尾


因为博主也是一个开发萌新 我也是一边学一边写 我有个目标就是一周 二到三篇 希望能坚持个一年吧 希望各位大佬多提意见,让我多学习,一起进步。


相关文章
|
3天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2
|
27天前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。HashSet基于哈希表实现,提供高效的元素操作;TreeSet则通过红黑树实现元素的自然排序,适合需要有序访问的场景。本文通过示例代码详细介绍了两者的特性和应用场景。
36 6
|
27天前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
37 3
|
28天前
|
存储 算法 Java
Java HashSet:底层工作原理与实现机制
本文介绍了Java中HashSet的工作原理,包括其基于HashMap实现的底层机制。通过示例代码展示了HashSet如何添加元素,并解析了add方法的具体过程,包括计算hash值、处理碰撞及扩容机制。
|
7天前
|
人工智能 监控 数据可视化
Java智慧工地信息管理平台源码 智慧工地信息化解决方案SaaS源码 支持二次开发
智慧工地系统是依托物联网、互联网、AI、可视化建立的大数据管理平台,是一种全新的管理模式,能够实现劳务管理、安全施工、绿色施工的智能化和互联网化。围绕施工现场管理的人、机、料、法、环五大维度,以及施工过程管理的进度、质量、安全三大体系为基础应用,实现全面高效的工程管理需求,满足工地多角色、多视角的有效监管,实现工程建设管理的降本增效,为监管平台提供数据支撑。
24 3
|
13天前
|
运维 自然语言处理 供应链
Java云HIS医院管理系统源码 病案管理、医保业务、门诊、住院、电子病历编辑器
通过门诊的申请,或者直接住院登记,通过”护士工作站“分配患者,完成后,进入医生患者列表,医生对应开具”长期医嘱“和”临时医嘱“,并在电子病历中,记录病情。病人出院时,停止长期医嘱,开具出院医嘱。进入出院审核,审核医嘱与住院通过后,病人结清缴费,完成出院。
42 3
|
18天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
21天前
|
移动开发 前端开发 JavaScript
java家政系统成品源码的关键特点和技术应用
家政系统成品源码是已开发完成的家政服务管理软件,支持用户注册、登录、管理个人资料,家政人员信息管理,服务项目分类,订单与预约管理,支付集成,评价与反馈,地图定位等功能。适用于各种规模的家政服务公司,采用uniapp、SpringBoot、MySQL等技术栈,确保高效管理和优质用户体验。
|
8天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
5天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
23 9