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…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向
在人工智能技术呈指数级发展的当下,大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性,吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型,成为释放其巨大潜力的关键所在&…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...
JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...
游戏开发中常见的战斗数值英文缩写对照表
游戏开发中常见的战斗数值英文缩写对照表 基础属性(Basic Attributes) 缩写英文全称中文释义常见使用场景HPHit Points / Health Points生命值角色生存状态MPMana Points / Magic Points魔法值技能释放资源SPStamina Points体力值动作消耗资源APAction…...
OpenHarmony标准系统-HDF框架之I2C驱动开发
文章目录 引言I2C基础知识概念和特性协议,四种信号组合 I2C调试手段硬件软件 HDF框架下的I2C设备驱动案例描述驱动Dispatch驱动读写 总结 引言 I2C基础知识 概念和特性 集成电路总线,由串网12C(1C、12C、Inter-Integrated Circuit BUS)行数据线SDA和串…...
本地部署drawDB结合内网穿透技术实现数据库远程管控方案
文章目录 前言1. Windows本地部署DrawDB2. 安装Cpolar内网穿透3. 实现公网访问DrawDB4. 固定DrawDB公网地址 前言 在数字化浪潮席卷全球的背景下,数据治理能力正日益成为构建现代企业核心竞争力的关键因素。无论是全球500强企业的数据中枢系统,还是初创…...
