Java - 提高-源码(6) - HashSet

【Java集合类】之 HashSet以及底层逻辑分析_hashset实现逻辑 首先先来研究一下帮助文档HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。HashSet 允许有 null 值。HashSet 是无序的,即不会记录插入的顺序。HashSet 不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。您必须在多线程访问时显式同步对 HashSet 的并发访问。HashSet 实现了 Set 接口。此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序; 阅读详情

HashSet源码解析

源码解析对应JDK1.7

JDK1.7源码下载地址:JDK1.7下载地址


HashSet源码中官方注释是这样描述的:

This class implements the Set interface, backed by a hash table (actually a HashMap instance). 
It makes no guarantees as to the iteration order of the set; 
in particular, it does not guarantee that the order will remain constant over time. 
This class permits the null element.
大意是:
此类实现了Set接口,由哈希表(实际上是HashMap实例)支持。
对集合的迭代次序不作任何保证; 特别是不能保证订单在一段时间内保持不变。
此类允许null元素。



首先记住结论:
a. HashSet 没有重复元素的集合。
b. HashSet 是无序的。
c. HashSet 元素允许为null。
d. HashSet 非线程安全


HashSet的构造函数
HashSet():
构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75。

HashSet(int initialCapacity):
构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)。

HashSet(int initialCapacity, float loadFactor):
构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和指定的加载因子。

HashSet(Collection<? extends E> c):
构造一个包含指定 collection 中的元素的新 set。



HashSet参数

// HashSet的底层容器,没错,是HashMap!
private transient HashMap<E, Object> map;

// Dummy value to associate with an Object in the backing Map
// 定义一个Object对象作为HashMap的value值
private static final Object PRESENT = new Object();


HashSet常用方法

add()方法

public boolean add(E e) {
	return map.put(e, PRESENT) == null;
}
add()方法底层调用的是HashMap的put方法;
这时候e就是key,PRESENT就是value。

public V put(K key, V value) {

	// 如果key为空,将null存放在table[0]第一个位置,这就是HashMap允许存null的原因
	if (key == null)
			return putForNullKey(value);

	// 计算key的hash值
	int hash = hash(key);

	// 根据hash码和数组长度,计算table数组下标
	int i = indexFor(hash, table.length);

	// 从i处开始迭代entry链表,找到key保存的位置
	for (Entry<K, V> e = table[i]; e != null; e = e.next) {
			Object k;
			// 判断该链条上是否有hash值相同的(key相同)
			// 若存在key相同,直接覆盖value,返回旧的value
			if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
					V oldValue = e.value;// 取出旧值
					e.value = value;// 赋新值
					e.recordAccess(this);
					return oldValue;// 返回旧值
			}
	}

	// 修改次数+1
	modCount++;

	// i处没有entry链表(该位置为空),将key,value添加至i处
	addEntry(hash, key, value, i);

	return null;
}
这个源码很熟悉吧..HashMap中的put方法。
当我们第一次插入的时候很顺利,调用addEntry(),插入到Entry中。


那么问题来了,HashSet是怎么通过HashMap来实现元素不重复的呢?
举个栗子:

HashSet<String> set = new HashSet<String>();
set.add("a");
set.add("a");
第一次add时候,调用put("a",PRESENT),之后没问题,看源码就行。
第二次add相同的数据,依旧调用put("a",PRESENT)

运行到这里:

// 从i处开始迭代entry链表,找到key保存的位置
for (Entry<K, V> e = table[i]; e != null; e = e.next) {
	Object k;
	// 判断该链条上是否有hash值相同的(key相同)
	// 若存在key相同,直接覆盖value,返回旧的value
	if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
			V oldValue = e.value;// 取出旧值
			e.value = value;// 赋新值
			e.recordAccess(this);
			return oldValue;// 返回旧值
	}
}
你看啊,因为两次的key是一样的,计算出来的下标也是一样的,这时候就开始比较key了
如果两个key一样,那么将新key的value覆盖旧key的value,也就是说,key始终没有发生变化!!

简单地说当key存在于HashMap的key时,会替换原有的value,但是key保持不变。
所以将一个已经存在的key元素添加到HashSet中,新添加的元素不会保存到HashMap中。


clear()方法

/**
* Removes all of the elements from this set. The set will be empty after
* this call returns.<br>
* 从该集合中删除所有元素。 此通话返回后,该设置将为空。
*/
public void clear() {
	map.clear();
}
调用了底层 map 的 clear 方法;

public void clear() {
	modCount++;
	Entry[] tab = table;
	for (int i = 0; i < tab.length; i++)
			tab[i] = null;
	size = 0;
	}
将 map 清空 ...


contains()方法

public boolean contains(Object o) {
	return map.containsKey(o);
}
底层调用了map的containsKey方法。

public boolean containsKey(Object key) {
	return getEntry(key) != null;
}
跟下去看getEntry()方法
final Entry<K, V> getEntry(Object key) {
	// 计算key的hash值
	int hash = (key == null) ? 0 : hash(key);

	// 根据hash值,算出下标位置,从table数组中取出Entry
	for (Entry<K, V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
			Object k;
			// 查找的key与entry中的key相同,则返回对应的value
			if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
					return e;
	}
	return null;
}
注释写的比较清楚了不解释了 ...


HashSet底层是基于HashMap实现的,如果之前HashMap看明白,看透了,HashSet也是很容易的。

BLHeli_S电调刷Bluejay固件实战:解锁双向DShot与RPM滤波全攻略 本文详细介绍了如何为BLHeli_S电调刷写开源Bluejay固件,以解锁双向DShot协议与RPM滤波等关键功能。内容涵盖硬件兼容性检查、固件刷写全流程、双向DShot启用与OSD报错解决方案,并对48kHz与96kHz PWM频率的选择提供了实战建议,帮助穿越机玩家在不更换硬件的前提下显著提升飞行性能与操控体验。 阅读详情

相关推荐

LVGL开发新选择:深度对比NXP GUI Guider与SquareLine Studio,免费版够用吗?

本文深度对比了LVGL开发中两款主流工具NXP GUI Guider与SquareLine Studio的核心差异,包括功能定位、设计能力、代码生成质量和硬件适配等方面。针对不同项目需求,分析了免费版工具的适用性,帮助开发者根据预算和功能需求做出明智选择。特别关注了GUI设计工具在嵌入式开发中的实际应用效果。

weixin_26976635的博客 427

关于Java集合

2011-01-04 22:51 转载自 xc_jetguo 最终编辑 xc_jetguo java 的魅力之一就是对多媒体的支持,Appley使得原来沉闷的网页变得 丰富起来,在java.applet中提供了很多功能强大的方法对多媒体的支 持。现在我们就j

YiRong 1666

AI视频生成技术研究报告:现状、挑战与展望

AI 视频生成技术概述:介绍 AI 视频生成技术的基本概念,回顾其发展历程,从早期依赖图像拼接的简单生成方式,到如今融合多种先进技术的复杂模型应用,梳理技术演进的关键节点和重要突破。同时,分析该技术在当前阶段的特点,包括生成视频的质量、速度、灵活性等方面,以及与传统视频制作方式的差异,阐述 AI 视频生成技术如何改变视频创作的流程和模式。技术实现路径分析。

daqsdfas的博客 4575

如何在Java 8中创建线程安全的ConcurrentHashSet

在JDK 8之前,无法在Java中创建大型,线程安全的ConcurrentHashSet。该java.util.concurrent包没有一个叫做ConcurrentHashSet的类,但是从JDK 8开始,可以使用新添加的keySet(默认值)和newKeySet()方法在Java中创建一个由ConcurrentHashMap支持的ConcurrentHashSet。这比旧的解决方案更好。key...

weixin_34126557的博客 781

ThingsBoard入门实战(二):ThingsBoard 设备接入

文章目录ThingsBoard 设备接入一、设备配置/设备类型二、设备三、设备接入HTTPCOAPMQTT四、下一步 ThingsBoard 设备接入 设备接入并不一定需要真正的设备,我们可以通过程序。或者命令来模拟设备,向平台发送信息。 这节我们先为用户分配一个设备,然后通过模拟设备命令更新设备的状态(遥测值)。 一、设备配置/设备类型 添加一个叫"路灯"的设备配置。 设备配置听起来比较抽象,可以认为是设备类型或者是设备类型的配置。实际上,ThingsBoard 中很多时候让选择设备类型,就是选的这个。

AIGC搞起 1万+

Device Mapper 代码分析

Device Mapper(DM)是Linux 2.6全面引入的块设备新构架,通过DM可以灵活地管理系统中所有的真实或虚拟的块设备。DM以块设备的形式注册到Linux内核中,凡是挂载(或者说“映射”)于DM结构下的块设备,不管他们是如何组织,如何通讯,在Linux看来都是一个完整的DM块设备。因此DM让不同组织形式的块设备或者块设备集群在Linux内核面前有一个完整统一的DM表示。一、DM

SonicLing的专栏 1万+

为什么ConcurrentHashMap没有ConcurrentHashSet

HashSet is based on HashMap. HashSet基于HashMap。 If we look at HashSet<E> implementation, eve

p15097962069的博客 979

摄像头visio_最全面弱电智能VISIO图标集(百个),高大上方案就靠这个了

原标题:最全面弱电智能VISIO图标集(百个),高大上方案就靠这个了不会用Visio,Visio画拓扑画的很丑,怎么办?本期sin66小编免费分享一份最全面的弱电智能VISIO图标集(百个)给大家,以后画拓扑、做方案,直接高大上起来!需要本期资料直接看文末!!接下来我们一起看一下这些Visio图标大全:我们从下图可以看出前端设备主要是由枪机,筒机,无线摄像头,半球,球机,USB摄像头等构成,对于绘...

weixin_39644915的博客 1万+

Java8源码-HashSet

今天开始学习HashSet。HashSet是依赖于HashMap的Set接口的实现,实际上是个HashMap的实例。如果对HashMap源码很熟悉,那么学习HashSet就会很简单了。HashSet的特点是不保证set的迭代顺序,特别是它不保证该顺序恒久不变,允许使用null 元素。本文将从数据结构、实现原理、源码等多个方面详细讲解HashSet。 数据结构 HashSet是依赖于Hash...

潘威威的博客 2090

《湖科大教书匠计算机网络》学习笔记总目录+思维导图

本篇文章是对《湖科大教书匠计算机网络》所有知识点的笔记总结归档和计算机网络的思维导图

weixin_73077810的博客 8230

矿石生成(1)

这个提供了标准化的矿石放置配置模板简化了常见和稀有矿石的配置过程遵循了Minecraft原版的世界生成模式提高了代码的可读性和可维护性通过使用这个类,模组开发者可以更轻松地配置矿石的生成规则,而不需要每次都手动编写完整的放置修饰符列表。这种设计模式在原版Minecraft和其他大型模组中也很常见,是一种良好的编程实践。// 导入语句...// 字段和方法...包声明表明这个类位于luckymod模组的WorldGen包中,专门处理世界生成相关配置。导入语句。

qq_24992377的博客 136

Java HashSet 的实现源码解析

HashSet 是一个没有重复元素的集合。基于HashMap实现。简介HashSet定义:public class HashSet<E> extends Abstr...

AI天才研究院 8737

从零训练Qwen3-VL

如果你未来想做的是「在公开权重上继续做大规模多模态 pretrain(比如换数据、换目标函数)」而不是在完全随机初始化上起步,这两类代码会比 Open-Qwen2VL 更直接。参考 Qwen2-VL / Qwen2.5-VL 披露的流程,可以大致推测 Qwen3-VL 也是类似的三阶段:(直接在学术算力(8×A100-40G)上从零预训练了一个 2B 参数的多模态 Qwen2-VL 风格模型:(的配置和训练脚本,理解它是如何把「任意 ViT + 任意 LLM + 任意图文数据」拼在一起的。

u013250861的博客 563

java-hashset 源码分析 3

HashMap` 的键唯一性保证了 `HashSet` 中元素的唯一性,而 `PRESENT` 常量则简化了 `HashMap` 的值管理。`LinkedHashSet` 是 `HashSet` 的一个子类,除了提供 `HashSet` 的所有功能外,还维护了元素的插入顺序。`HashSet` 的设计与实现主要依赖于 `HashMap`,通过对 `HashMap` 的封装,提供了集合的功能。`HashSet` 通过 `HashMap` 的动态扩容机制来保持较低的负载因子,从而提高查询和插入操作的效率。

weixin_41247813的博客 947

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Java的HashSet源码分析

在编程的世界里,有一种神奇的工具,它小巧却强大,灵活而可靠,它就是 HashSet。然而,你是否曾经好奇过,这么强大的工具,其背后的实现原理是怎样的呢?今天,让我们一起揭开 HashSet 源码的神秘面纱,探索这个 Java 世界中的神奇数据结构。首先,我们需要明白,HashSet 并不是一个简单的集合,它是基于哈希表实现的一种集合。哈希表是一种数据结构,通过哈希函数将元素映射到数组的一个位置,实现快速的查找。而 HashSet 则在此基础上,增加了一些额外的功能,使得它在存储和查找元素时更加高效。

编程思维 1229

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

【Java集合类】之 HashSet以及底层逻辑分析

HashSet基于HashMap来实现的,是一个不允许有重复元素的集合。 HashSet允许有null值。HashSet是无序的,即不会记录插入的顺序。 HashSet不是线程安全的,如果多个线程尝试同时修改HashSet,则最终结果是不确定的。您必须在多线程访问时显式同步对HashSet的并发访问。 HashSet实现了Set接口。此类实现Set接口,由哈希表(实际上是一个HashMap实例)支持。它不保证set的迭代顺序;............

鱼干的博客 1729

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

HashSet源码分析

阅读本文章之前推荐先阅读博主关于HashMap的文章: HashMap源码分析 + 面试题 HashSet源码分析 文章目录HashSet源码分析一、基本介绍二、源码分析1. 成员变量2. 构造方法3. 添加方法4. 删除方法5. 查询方法6. 遍历方法三、总结 一、基本介绍 底层实现基于 HashMap,所以迭代时不能保证按照插入顺序或者其它顺序进行迭代 add、remove、contanins、size 等方法的耗时性能,是不会随着数据量的增加而增加的,这个主要跟 HashMap 底层的数据结构

立志成为一个前端、后端、测试全方位发展的程序员 432

探秘 Java HashSet:从源码洞悉其使用原理

HashSet是 Java 集合框架中的一个类,它实现了Set接口。Set接口代表一种不包含重复元素的集合,即集合中的每个元素都是唯一的。HashSet基于哈希表(实际上是HashMap)来存储元素,它通过哈希函数将元素映射到哈希表的特定位置,从而实现快速的元素查找和插入操作。由于哈希表的特性,HashSet不保证元素的存储顺序,也就是说,元素在HashSet中的存储顺序可能与插入顺序不同。HashSet是 Java 集合框架中一个非常实用的集合实现,它基于HashMap不允许重复元素HashSet。

Android开发领域创作者 684

Java HashSet 散列集合

本文介绍了 Java 中 HashSet(散列集合)的相关内容。。。

Regino的博客 1232

[JDK1.6] JAVA集合框架 HashSet 源码浅析

文章目录一 简介:HashSet 字段属性:Set 初始化HashSet 存储元素 add(E)其他方法都委托给了 HashMap获取迭代器 iterator() 源码来自 JDK1.6 一 简介: 此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。 此类为基本操作提供了稳定性能...

程序猿-Jojo 518

Java集合之HashSet源码剖析(jdk1.8)

Java集合之HashSet源码剖析(jdk1.8) 文章目录Java集合之HashSet源码剖析(jdk1.8)1、简介2、源码解析1、属性2、构造方法3、重要方法3、总结 1、简介 HashSet是Set接口下常用的实现类。 HashSet的实现主要使用HashMap的key来满足Set的特性:不重复,并且也是无序的。 HashSet的继承图谱如下: 实现的都是些基础接口。 2、源码解析 H...

cgl_dong的博客 344

09、HashSet、TreeSet、LinkedHashSet 源码解析

Set类集合通过组合不同的Map,实现各种Set的功能,HashSet组合的是HashMap,TreeSet组合的是TreeMap,而LinkedHashSet则是继承HashSet,HashSet和TreeSet之所以采用组合而不是继承的方式,是因为: 继承表示父子类是同一个事物,而 Set 和 Map 本来就是想表达两种事物,所以继承不妥,而且 Java 语法限制,子类只能继承一个父类,使用继承后续难以扩展; 组合更加灵活,可以任意的组合现有的基础类,并且可以在基础类方法的基础上进行扩展、编排等,而且

hsg_happyLearning的博客 294

[源码解析]HashSet

本篇文章是我解析Java-API的笔记,更多的是从方法着手,少对类的整体情况进行说明,故并不详尽,可供大家参考。 如果文中阐述不全或不对的,多多交流。

进步*于辰的博客 1万+

HashSet 源码分析 -- java 1.8

Java8 HashSet原理 概述 在官方文档中是这样描述HashSet的: This class implements the Set interface, backed by a hash table (actually a HashMap instance). It makes no guarantees as to the iteration order of the set; i...

qq_20064763的博客 249

Java HashSet的去重问题

对象去重失败原因以及解法

麻辣香蝈蝈的博客 1289

【Java从入门到放弃 之 HashMap 和 HashSet】

概述定义:HashMap 是一种以哈希表为基础的实现,提供了常数时间复杂度 O(1) 的基本操作(如 get 和 put),假设哈希函数分布均匀。特点:线程不安全:与 Hashtable 不同,HashMap 不是同步的,因此在多线程环境中需要额外的同步机制。允许一个 null 键和多个 null 值:可以包含一个 null 键和任意数量的 null 值。无序:不保证元素的迭代顺序;如果需要有序,可以考虑使用 LinkedHashMap 或 TreeMap。内部工作原理。

Snow的博客 1697
上一篇: Java - 提高-源码(5) - HashTable
下一篇: Java - 提高(7) - 内部类
Simba_cheng
博客等级 码龄11年 250粉丝 203原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值