HashSet及其实现原理
目录
- 一、Set
- 二、HashSet
- 三、HashSet的实现原理
- 四、HashSet的线程安全与顺序
- 1、线程安全
- 2、有序性
一、Set
Set 接口是 java.util 包下的一个集合接口,它继承自 Collection 接口。Set 接口定义了一个不允许包含重复元素的集合。Set 接口的实现类主要有 HashSet、LinkedHashSet 和 TreeSet。
以下是 Set 接口的一些关键特性:
- 不包含重复元素:Set 接口的实现类不允许集合中存在两个相等的对象。
- 无序性:大多数 Set 实现(如 HashSet)不保证集合的迭代顺序;特别是它不保证该顺序恒久不变。
- 唯一性:Set 接口的 add 方法在添加元素时,如果集合中已经存在该元素,则不会再次添加。
- 可选的排序:某些 Set 实现(如 TreeSet)会根据其元素的自然顺序或者构造集合时所指定的比较器来对元素进行排序。
关键特性总结:无序不重复、可选排序
Set 接口定义了以下方法:
- add(E e):添加元素,如果元素已存在则返回 false,否则添加后返回 true。
- remove(Object o):如果集合中存在该元素,则移除它并返回 true,否则返回 false。
- contains(Object o):检查集合是否包含指定元素。
- size():返回集合中的元素数量。
- isEmpty():检查集合是否为空。
- clear():移除集合中的所有元素。
- iterator():返回集合的迭代器。
二、HashSet
HashSet 是 Java 集合框架中的一个非常常用的集合类,它是 java.util包的一部分。HashSet继承自 AbstractSet 类,实现了 Set接口。底层基于HashMap实现。只存储元素,不存储键值对,它不允许重复的元素。
private transient HashMap<E,Object> map;// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();/*** Constructs a new, empty set; the backing <tt>HashMap</tt> instance has* default initial capacity (16) and load factor (0.75).*/
public HashSet() {map = new HashMap<>();
}
以下是 HashSet
的一些关键特性:
- 不允许重复:
HashSet
不允许集合中有重复的元素。如果尝试添加一个已经存在的元素,HashSet
会保持原样,不会添加新元素。 - 无序:
HashSet
不保证元素的顺序,每次迭代集合时元素的顺序可能不同。 - 基于哈希表:
HashSet
内部使用HashMap
实现,每个元素都作为HashMap
的一个键,而对应的值是一个虚拟对象(通常是HashSet
内部的一个静态对象)。 - 性能:由于
HashSet
基于哈希表,因此它在添加、删除和查找元素时通常提供常数时间的性能(即 O(1) 时间复杂度),但这取决于哈希函数的质量和冲突的数量。 - 不保证线程安全:
HashSet
不是线程安全的。如果需要线程安全的集合,可以使用Collections.synchronizedSet(new HashSet<>())
包装HashSet
,或者使用ConcurrentHashMap
的键集。 - 可以包含
null
元素:HashSet
允许包含一个null
元素,因为HashMap
允许null
作为键。 - 迭代器:
HashSet
提供迭代器来遍历集合中的所有元素。
主要特性总结: 无序不重复,只存储元素不存储键值对,线程不安全。
三、HashSet的实现原理
HashSet 是 Java 中的一个集合类,它基于 HashMap实现。下面是 HashSet的实现原理:
-
基于 HashMap:
- HashSet 的内部实际上是使用一个
HashMap
来存储元素的。 - 每个 HashSet 元素都作为
HashMap
的键,而对应的值是一个固定的虚拟对象(通常是一个静态的布尔值)。
- HashSet 的内部实际上是使用一个
-
元素唯一性:
- 由于
HashMap
的键是唯一的,所以 HashSet 能够保证元素的唯一性。
- 由于
-
添加元素:
-
当你向 HashSet添加一个元素时,它实际上是将该元素作为键添加到内部的
HashMap
中。 -
如果
HashMap
中已经存在这个键,则HashSet
会认为元素已经存在,不会添加重复的元素。public boolean add(E e) {return map.put(e, PRESENT)==null; }
-
-
删除元素:
- 当你从
HashSet
删除一个元素时,它实际上是从内部的HashMap
中删除对应的键。
- 当你从
-
查找元素:
- 当你检查
HashSet
是否包含某个元素时,它实际上是在内部的HashMap
中查找这个键。
- 当你检查
-
迭代器:
-
HashSet
的迭代器实际上是迭代内部HashMap
的键集。public Iterator<E> iterator() {return map.keySet().iterator(); }
-
-
性能:
HashSet
的添加、删除和查找操作的性能通常都是常数时间的(O(1)),这得益于HashMap
的性能。
-
容量和加载因子:
HashSet
继承了HashMap
的容量和加载因子的概念,这些参数影响HashSet
的性能和内存使用。
-
并发性:
- HashSet不是线程安全的。如果你需要线程安全的集合,可以使用
Collections.synchronizedSet(new HashSet<>(...))
或者ConcurrentHashMap
的键集。
- HashSet不是线程安全的。如果你需要线程安全的集合,可以使用
-
序列化:
- HashSet 实现了
Serializable
接口,这意味着它可以被序列化和反序列化。
- HashSet 实现了
四、HashSet的线程安全与顺序
1、线程安全
HashSet 是非线程安全的。这意味着多个线程同时修改 HashSet可能会导致不可预知的行为。如果多个线程需要访问和修改同一个 HashSet实例,必须通过外部同步来确保线程安全。
如果你需要线程安全的 Set
集合,可以考虑以下替代方案:
-
Collections.synchronizedSet:通过这个静态方法包装一个 HashSet,可以提供简单的线程安全。但是,这种方法的并发性能较低,因为每次访问都需要获取锁。
-
ConcurrentHashMap 的
keySet
方法:ConcurrentHashMap
提供了keySet
方法,它返回一个线程安全的Set
视图。这个Set
支持更高效的并发访问。 -
CopyOnWriteArraySet:这是一个线程安全的
Set
实现,它在每次修改(添加或删除元素)时都会复制整个底层数组。这种方法适用于读多写少的场景。import java.util.Collections; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet;public class ThreadSafeSetExample {public static void main(String[] args) {// 使用 Collections.synchronizedSet 包装 HashSetSet<String> syncSet = Collections.synchronizedSet(new HashSet<>());syncSet.add("Element1");syncSet.add("Element2");// 使用 CopyOnWriteArraySetSet<String> copyOnWriteSet = new CopyOnWriteArraySet<>();copyOnWriteSet.add("Element1");copyOnWriteSet.add("Element2");// 迭代两个线程安全的 SetSystem.out.println("Synchronized Set: " + syncSet);System.out.println("CopyOnWriteArraySet: " + copyOnWriteSet);} }
2、有序性
HashSet 不保证元素的顺序。它基于 HashMap实现,而 HashMap不保证键的顺序。因此,每次迭代 HashSet 时元素的顺序可能不同。
如果你需要一个有序的 Set
集合,你可以考虑以下几种方法:
-
TreeSet
: TreeSet 是一个有序的 Set集合,它基于红黑树实现。TreeSet可以确保元素处于排序状态,无论是按照自然顺序还是根据提供的 Comparator。 -
LinkedHashSet
: LinkedHashSet维护了元素的插入顺序,或者在构造时指定的最近期访问顺序。它内部使用 LinkedList 来维护元素的顺序,同时使用 HashMap 来保证元素的唯一性。 -
使用
HashSet
与额外的数据结构: 如果你需要保留 HashSet 的所有特性,并且只需要偶尔的顺序访问,你可以在需要的时候将 HashSet 元素添加到一个 TreeSet或 LinkedHashSet 中,进行排序操作。import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors;public class OrderedSetExample {public static void main(String[] args) {Set<Integer> hashSet = new HashSet<>();hashSet.add(5);hashSet.add(1);hashSet.add(4);hashSet.add(2);// 仅在需要有序时进行排序Set<Integer> sortedSet = hashSet.stream().collect(Collectors.toCollection(TreeSet::new));for (Integer number : sortedSet) {System.out.println(number);}} }
-
自定义有序 Set实现: 如果你有特殊的排序需求,你可以创建自己的
Set
实现,继承AbstractSet
类,并使用你选择的任何数据结构(如数组、链表等)来维护元素的顺序。
相关文章:

HashSet及其实现原理
目录 一、Set二、HashSet三、HashSet的实现原理四、HashSet的线程安全与顺序1、线程安全2、有序性 一、Set Set 接口是 java.util 包下的一个集合接口,它继承自 Collection 接口。Set 接口定义了一个不允许包含重复元素的集合。Set 接口的实现类主要有 HashSet、Lin…...

反序列化漏洞练习1
根据代码可以看出来sis类只是接收了参数cmd,下边是通过get获得cmd的值,所以可以在序列化过程中直接为cmd赋值。 根据源码编写序列化代码 <?php class sis{public $cmdsystem("whoami");?>;public function __wakeup(){eval($this-&g…...

树莓派Pico2(RP2350)开发环境搭建
树莓派Pico2(RP2350)开发环境搭建 文章目录 树莓派Pico2(RP2350)开发环境搭建1、RP2350介绍2、开发环境搭建3、工程编译4、固件下载Raspberry Pi再次通过推出RP2350 MCU突破了微控制器设计的界限。这款微控制器是之前RP2040的重大升级,带来了更强大的性能、高级安全功能,…...

vue 路由中使用keepAlive在这个组件中使用onActivated
onMounted: 在组件挂载时触发一次。onActivated: 当 keep-alive 组件从缓存中被激活时触发。如果你将当前组件包裹在 keep-alive 中,激活时会调用此钩子。onDeactivated: 当 keep-alive 组件被缓存时触发。 注意事项 onActivated 只在组件从 keep-alive 缓存中恢复…...

医学数据分析实训 项目一 医学数据采集
项目一 医学数据采集 一、实践目的 了解医学数据的特点;熟悉常见的医学公共数据库的使用方法;掌握获取医学数据的方法; 二、实践平台 操作系统:Windows10 及以上Python 版本:3.8.x 及以上PyCharm 或 Anoconda 集成…...

《Oracle(一)- 基础》
文章目录 一、Oracle简介(一)什么是ORACLE(二)ORACLE 体系结构1.数据库2.实例3.数据文件(dbf)4.表空间5.用户 二、ORACLE 安装与配置(一)VMware 挂载 windows server 2003࿰…...

Unity Resource System 优化笔记
Unity Resources System 定义 Resources System允许开发者在项目中的Resources文件夹下存放一个或多个资源文件夹,并且可以在Unity运行时通过Unity提供的API对资源和对象进行加载和卸载。 如果Resources中的文件结构复杂,内容多,会给应用常…...

Flutter之SystemChrome全局设置
一、简介 SystemChrome作为一个全局属性,很像 Android 的 Application,功能很强大。 二、使用详解 2.1 setPreferredOrientations 设置屏幕方向 在我们日常应用中可能会需要设置横竖屏或锁定单方向屏幕等不同要求,通过 setPreferredOrien…...

Windows11 WSL2的ubuntu 22.04中拉取镜像报错
问题描述 在windows11 WSL2的ubuntu 22.04中拉取镜像报错。错误为: Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting header…...

【Linux】多线程:线程同步、条件变量
目录 一、同步的概念 为什么需要同步呢? 二、条件变量 条件变量的相关概念 1、条件变量的初始化:静态初始化、动态初始化 2、条件变量的等待:pthread_cond_wait函数 工作原理及流程【重要!】 关键点总结 3、条件变量的激…...

【Android Studio】使用雷电模拟器调试
文章目录 进入开发者模式使雷电模拟器adb连接PC测试 进入开发者模式 多次点击版本号 -开区USB调试 使雷电模拟器adb连接PC 写cmd脚本 雷电模拟器端口为5555 ,脚本内容如下: adb.exe connect 127.0.0.1:5555双击bat脚本文件 测试...

你必须知道的C语言问题(9)
问:如下代码,两个结构体类型成员变量相同,只是成员顺序不同,为什么大小不同? #include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h>typedef struct _test1{uint…...

如何通过网络找到自己想要的LabVIEW知识?
学习LabVIEW或其他编程技术时,无法依赖某一篇文章解决所有问题。重要的是通过多种途径获取灵感,并学会归纳总结,从而逐渐形成系统性的理解。这种持续学习和总结的过程是技术提升的基础。通过网络找到所需的LabVIEW知识可以通过以下几个步骤进…...

SCRM电商管理后台Axure高保真原型 源文件
在电商行业蓬勃发展的今天,企业急需一个全面的客户关系管理(CRM)系统来优化他们的电商运营。我们的Scrm电商管理后台应运而生,它不仅是一个集中化的管理平台,更是企业提升客户互动和销售业绩的得力助手。 预览地址 ht…...

重载new,delete , RTTI,类成员指针
重载new,delete 执行过程 重载new,delete 和普通的运算符重载不同,并非重载new,delete 的行为,而是改变内存分配的方式,将对象放置在特定的内存空间中 new运算符操作: 调用STL标准模板库的…...

基于SSM+Vue+MySQL的在线医疗服务系统
系统展示 用户前台界面 管理员后台界面 系统背景 随着医疗信息化的快速发展和患者对便捷医疗服务需求的日益增长,开发一个高效、可靠的在线医疗服务系统显得尤为重要。基于SSM(SpringSpring MVCMyBatis)框架、前端采用Vue.js、后端连接MySQL数…...

Windows 11上pip报‘TLS/SSL connection has been closed (EOF) (_ssl.c:1135)‘的解决方法
这个只是简单记录一下,可能是我用了代理的缘故,即便是把源换成国内的,例如阿里云,也会报错,例如: pip install matplotlib Looking in indexes: https://mirrors.aliyun.com/pypi/simple/, https://pypi.or…...

53 - I. 在排序数组中查找数字 I
comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9%A2%9853%20-%20I.%20%E5%9C%A8%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84%E4%B8%AD%E6%9F%A5%E6%89%BE%E6%95%B0%E5%AD%97%20I/README.md 面试题 53 - I. 在排序数组中查找数字 …...

基于 TDMQ for Apache Pulsar 的跨地域复制实践
导语 自2024年9月6日起,TDMQ Pulsar 版专业集群支持消息、元数据两级跨地域复制功能,消息级复制解决用户全球地域的数据统一归档问题,元数据级复制提供解决用户核心业务跨地域容灾的场景。 用户在跨地域场景遇到的疑问和挑战 在跨地域相关…...

无线通信感知/雷达系统算法专业技术栈
无论是在工业界还是在学业界,无线通信感知一体化都是一个热门的方向,作为一个24届毕业生,刚好处于行业当中,就总结一下自己浅薄认知下,自己觉得已经掌握或者应该掌握的技术栈和专业能力,与大家共勉。 Rada…...

离谱碾压!奇安信中标:高出第二名近70分!
2024年08月09日,广东省政务服务和数据管理局,近日发布了网络安全第三方服务(2024年)项目之关基检查及重要政务应用安全检查服务招标公告! 预算金额:2,896,200.00元,其中安全检查服务包…...

HOT 100(七)栈、堆、贪心算法
一、栈 1、每日温度 使用单调递减栈来解决。主要思路是遍历temperatures数组,利用栈来存储还没有找到比当前温度高的天数的索引。当遇到比栈顶索引所对应温度更高的温度时,就可以确定当前这一天的温度比之前那一天高。索引的差值就是等待的天数。 求一…...

速盾:高防服务器租用需要注意什么事项
在当今互联网时代,网络安全问题日益严峻。各种网络攻击手段层出不穷,给企业和个人的网站带来了巨大的安全威胁。为了保障网站的安全稳定运行,高防服务器成为了许多人的选择。而在租用高防服务器时,需要注意以下几个事项。 一、选择…...

【数据库】MySQL内置函数
本篇分享一些在MySQL中常见的一些内置函数,如日期函数,字符串函数和数学函数,以方便于操作数据库中的数据。 1.日期函数 我们先整体观察一下这些函数再讲解案例 日期函数使用起来都非常就简单 获得年月日: select current_dat…...

Promise查漏及回调地狱结构优化
目录 前言一、执行器函数的执行顺序二、如何在then()中抛出错误三、期约的"非重入"特性四、串行化期约五、应对回调地狱结语 前言 依据《JavaScript高级程序设计》对Promise期约相关进行查缺补漏. 一、执行器函数的执行顺序 执行器函数虽作为期约的参数, 却是期约的…...

SpringCloud-05 Resilience4J 服务降级和熔断
服务雪崩:指在多个服务之间存在依赖关系时,当一个服务发生故障或不可用时,导致其他服务也无法正常工作的情况。这种现象通常是因为服务之间的依赖关系过于紧密,当一个服务发生故障时,其他服务无法正确处理该服务的请求…...

哈希表、算法
哈希表 hash: 在编程和数据结构中,"hash" 通常指的是哈希函数,它是一种算法,用于将数据(通常是字符 串)映射到一个固定大小的数字(哈希值)。哈希函数在哈希表中尤为重要…...

变更AWS EC2 实例配置或实例类型
在本文中,九河云将带您了解如何更改由 Amazon Elastic Block Store (EBS) 支持的 Amazon Elastic Compute Cloud (EC2) 实例的类型。更改实例类型可以优化成本和性能,使其更符合您的应用程序需求。 准备工作 在开始之前,请确保您已完成以下…...

【前端】ref引用的作用
首先,我们要明确一点,使用vue的好处是: 想要减少开发者直接操作dom元素。使用组件模版,实现代码的服用。 ref的属性的实现是为了取代原生js中使用id、class等标识来获取dom元素。 helloworld组件 <template><div clas…...

运用Java实现倒计时功能
这个功能其实是比较好实现的,一般来说java中实现倒计时有两种方法: 1、使用 scheduledexecutorservice创建一个可重复执行的任务,直到时间到: ScheduledExecutorService 是 Java 中一种用于安排延迟或定期任务的工具。我们可以使…...