HashSet的源码剖析和static,final的作用

一、HashSet源码简析

HashSet 是 Java 集合框架中的一个重要类,它实现了 Set 接口,用于存储不重复的元素。HashSet 内部实际上是通过 HashMap 来实现的,其中每个元素都是 HashMap 的一个键,而值则是一个固定的对象(通常是 PRESENT,一个 HashSet 的静态成员变量)。这种实现方式使得 HashSet 的添加、删除和查找操作都具有接近常数时间的性能。

下面是一个简化的 HashSet 源码剖析,以帮助你理解其内部工作机制:

成员变量

// HashMap 用于存储元素
private transient HashMap<E,Object> map;// 一个用于表示 HashSet 中值的对象
private static final Object PRESENT = new Object();

构造函数

// 默认构造函数,创建一个空的 HashSet
public HashSet() {map = new HashMap<>();
}// 带有初始容量的构造函数
public HashSet(int initialCapacity) {map = new HashMap<>(initialCapacity);
}// 带有初始容量和加载因子的构造函数
public HashSet(int initialCapacity, float loadFactor) {map = new HashMap<>(initialCapacity, loadFactor);
}

添加元素

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

当调用 add 方法时,实际上是在 HashMap 中添加了一个键值对,其中键是要添加的元素,值是 PRESENT。如果添加成功(即之前该键不存在于 HashMap 中),则返回 true;否则返回 false

删除元素

public boolean remove(Object o) {return map.remove(o) == PRESENT;
}

删除操作实际上是在 HashMap 中删除指定的键。如果删除成功且被删除的值是 PRESENT,则返回 true;否则返回 false

查找元素

public boolean contains(Object o) {return map.containsKey(o);
}

查找操作实际上是检查指定的键是否存在于 HashMap 中。

遍历元素

遍历 HashSet 中的元素通常通过 Iterator 或增强型 for 循环来完成,这些操作最终都是基于 HashMap 的键集合的遍历。

注意事项

  • 由于 HashSet 不保证元素的迭代顺序,因此每次遍历 HashSet 时,元素的顺序可能会有所不同。
  • 由于 HashSet 是基于 HashMap 实现的,因此其性能特性(如时间复杂度)与 HashMap 相似。添加、删除和查找操作的时间复杂度通常是常数时间,但在极端情况下(如哈希冲突很多时)可能会退化为线性时间。

这只是一个简化的源码剖析,实际的 HashSet 实现可能包含更多的优化和特性。为了更深入地了解 HashSet 的工作原理,建议查阅 Java 官方文档或源代码。

二、在 HashSet 中将 Object PRESENT = new Object() 设置为 static final 属性主要有以下几个原因:

HashSet 中将 Object PRESENT = new Object() 设置为 static final 属性主要有以下几个原因:

  1. 节约内存空间PRESENT 对象在 HashSet 中用作所有元素的“值”。由于 HashSet 的内部实现是基于 HashMap 的,而 HashMap 存储的是键值对,HashSet 需要一个占位符作为值。通过将 PRESENT 设置为 static final,这个对象只会在类加载时创建一次,并被所有 HashSet 实例共享。这避免了为每个 HashSet 实例都创建一个新的 Object 实例,从而节约了内存空间。

  2. 保证值的不变性:由于 PRESENT 是一个 final 对象,它的引用是不可变的。这意味着一旦 PRESENT 被赋值,就不能再被重新赋值指向其他对象。这确保了 HashSet 的内部实现不会因为 PRESENT 值的改变而出错。

  3. 代码可读性:使用 PRESENT 作为占位符值可以使代码更加清晰和易于理解。当其他开发者看到 PRESENT 被用作值时,他们可以立即理解这是 HashSet 的一个内部实现细节,而不是一个需要特别关注的业务逻辑值。

  4. 线程安全:虽然 HashSet 本身不是线程安全的,但将 PRESENT 设置为 static final 可以确保在多线程环境下,PRESENT 的引用不会被意外修改。这有助于减少并发编程中的潜在错误。

综上所述,将 Object PRESENT = new Object() 设置为 static final 属性是出于性能、代码可读性和线程安全性的考虑。这种设计使得 HashSet 的内部实现更加高效和健壮。

三、是不是只要设置为static的对象,那么这个对象只会在类加载时创建一次?并被所有这个类实例共享

是的,您的理解是正确的。在Java中,当一个字段(无论是基本类型还是对象引用)被声明为static时,这个字段就属于类本身,而不是类的任何特定实例。因此,static字段的初始化只会在类首次被加载到JVM时发生一次,而不是每次创建类的新实例时都发生。

具体来说:

  • 当类被加载到JVM时,它的static字段会被初始化。如果是引用类型,那么会分配内存空间,并赋予默认值(对于对象引用类型,默认值是null)。然后,如果提供了显式的初始化表达式或初始化块,这些会按照它们在代码中出现的顺序被执行。
  • 一旦static字段被初始化,它就会一直存在于内存中,直到类被卸载(这通常发生在类加载器被垃圾回收时)。
  • 类的所有实例都共享相同的static字段。因此,通过一个实例修改static字段的值会影响到所有其他实例。

例如:

public class MyClass {public static int staticVar = 42;public int instanceVar;public MyClass(int value) {instanceVar = value;}public static void main(String[] args) {MyClass obj1 = new MyClass(10);MyClass obj2 = new MyClass(20);System.out.println(MyClass.staticVar); // 输出 42,因为staticVar是静态的,只有一个值MyClass.staticVar = 50; // 修改静态变量的值System.out.println(obj1.staticVar); // 输出 50,因为obj1和obj2共享这个静态变量System.out.println(obj2.staticVar); // 输出 50// 注意:实例变量不会被共享System.out.println(obj1.instanceVar); // 输出 10System.out.println(obj2.instanceVar); // 输出 20}
}

在这个例子中,staticVarMyClass的一个static字段,它在类加载时初始化,并且obj1obj2两个实例共享这个字段。当我们通过MyClass.staticVar = 50;修改它的值时,这个修改会反映在所有通过MyClass访问这个字段的地方。相反,instanceVar是实例字段,每个MyClass的实例都有它自己的副本。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/3981.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32的Flash读写保护

参考链接 STM32的Flash读写保护&#xff0c;SWD引脚锁的各种解决办法汇总&#xff08;2020-03-10&#xff09;-腾讯云开发者社区-腾讯云 (tencent.com)https://cloud.tencent.com/developer/article/1597959 STM32系列芯片Flash解除写保护的办法 - 知乎 (zhihu.com)https://zh…

调度问题变形的贪心算法分析与实现

调度问题变形的贪心算法分析与实现 一、问题背景与算法描述二、算法正确性证明三、算法实现与分析四、结论 一、问题背景与算法描述 带截止时间和惩罚的单位时间任务调度问题是一个典型的贪心算法应用场景。该问题的目标是最小化超过截止时间导致的惩罚总和。给定一组单位时间…

通过idea插件一键将jar包发布到阿里云服务器部署

通过idea插件一键将jar包发布到阿里云服务器部署_idea发包工具-CSDN博客

【AIGC调研系列】大型语言模型如何减少幻觉生成

在解读大型语言模型&#xff08;LLMs&#xff09;中的长格式事实性问题时&#xff0c;我们首先需要认识到这些模型在生成内容时可能会产生与既定事实不一致的情况&#xff0c;这种情况通常被称为“幻觉”[2][3]。这种现象不仅可能导致信息的误传&#xff0c;还可能对社会造成误…

责任链模式的应用

设计模式责任链模式 责任链模式介绍 概述 责任链模式是一种行为型模式。责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求…

使用nssm把批处理(.bat)文件设置为Windows 服务

本文以canal为例 使用nssm把批处理(.bat)文件设置为Windows 服务 下载 nssm&#xff1a; 前往 nssm 官方网站 下载适用于系统的 nssm 工具。 安装 nssm&#xff1a; 将下载的 nssm 压缩文件解压缩到一个合适的位置&#xff0c;如 D:\nlc\6.Canal-1.1.5\nssm-2.24\win64\nss…

【每日一题】补档 CF1065 C. Make It Equal | 思维 | 中等

题目内容 原题链接 给定一个长度为 n n n 的数组 a a a &#xff0c;每次操作可以选择一个数 x x x &#xff0c;将所有大于 x x x 的数都下降为 x x x &#xff0c;一次操作的下降总代价为 s s s &#xff0c;要求 s ≤ k s\leq k s≤k &#xff0c;问需要多少次操作使…

深度学习运算:CUDA 编程简介

一、说明 如今&#xff0c;当我们谈论深度学习时&#xff0c;通常会将其实现与利用 GPU 来提高性能联系起来。GPU&#xff08;图形处理单元&#xff09;最初设计用于加速图像、2D 和 3D 图形的渲染。然而&#xff0c;由于它们能够执行许多并行操作&#xff0c;因此它们的实用性…

kafka启动报错(kafka.common.InconsistentClusterIdException)

文章目录 前言kafka启动报错(kafka.common.InconsistentClusterIdException)1. 查找日志2. 定位问题/解决 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不…

SpringCloud系列(17)--将服务消费者Consumer注册进Zookeeper

前言&#xff1a;在上一章节中我们把服务提供者Provider注册进了Zookeeper&#xff0c;而本章节则是关于如何将服务消费者Consumer注册进Zookeeper 1、再次创建一个服务提供者模块&#xff0c;命名为consumerzk-order80 (1)在父工程下新建模块 (2)选择模块的项目类型为Maven并…

稳态视觉诱发电位 (SSVEP) 分类学习系列 (4) :Temporal-Spatial Transformer

稳态视觉诱发电位分类学习系列:Temporal-Spatial Transformer 0. 引言1. 主要贡献2. 提出的方法2.1 解码的主要步骤2.2 网络的主要结构 3. 结果和讨论3.1 在两个数据集下的分类效果3.2 与基线模型的比较3.3 消融实验3.4 t-SNE 可视化 4. 总结欢迎来稿 论文地址&#xff1a;http…

【后端学习笔记·Golang】手机短信验证

文章目录 手机号码验证前置准备开通阿里云sms服务获取AccessKey并下载sdk 生成随机验证码将验证码发送到用户手机接口发送验证码校验验证码 手机号码验证 流程&#xff1a; 接收用户请求后生成随机验证码&#xff0c;并将验证码存入Redis中&#xff0c;并设置TTL通过阿里云sd…

Qt : 实现串口的同步和异步读写消息

一、同步/异步 在串口通信中&#xff0c;同步和异步读写消息是两种常见的通信模式。下面简要介绍它们的区别和示例&#xff1a; 同步读写消息 同步读写&#xff1a;在同步通信中&#xff0c;发送方发送数据后会等待接收方的响应&#xff0c;直到接收到响应后才继续执行后续操…

【C++】C++ 锁(std::mutex)的使用及其使用

在C中&#xff0c;锁是一种同步机制&#xff0c;用于保护共享资源在多线程环境下的访问安全&#xff0c;防止因并发访问导致的数据不一致、竞态条件等问题。 以下是对C中锁相关概念、类型以及使用方法的详细介绍&#xff1a; 1. 互斥锁&#xff08;Mutex&#xff09; 互斥锁…

【进阶六】Python实现SDVRPTW(需求拆分)常见求解算法——禁忌搜索+模拟退火算法(TS+SA)

基于python语言&#xff0c;采用经典禁忌搜索&#xff08;TS&#xff09;模拟退火&#xff08;SA&#xff09;对 带硬时间窗的需求拆分车辆路径规划问题&#xff08;SDVRPTW&#xff09; 进行求解。 目录 往期优质资源1. 适用场景2. 代码调整2.1 需求拆分2.2 需求拆分后的服务时…

EureKa技术解析:科技行业的革新风暴(ai写作)

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

如何驱动消费者自我裂变,助力平台引流与卖货双重提升

大家好&#xff0c;我是微三云周丽 在浩瀚的商业海洋中&#xff0c;电商行业一直以其独特的魅力和无限的可能性吸引着众多创业者和投资者的目光。近年来&#xff0c;一种被誉为电商模式中的“神盘”——众筹卖货模式&#xff0c;正悄然崭露头角&#xff0c;以其独特的运作方式…

Docker 入门篇(二)-- Linux 环境离线安装

引言 docker 系列文章&#xff1a; Docker 入门篇&#xff08;一&#xff09;-- 简介与安装教程&#xff08;Windows和Linux&#xff09; 一、安装环境准备 centos &#xff1a;CentOS Linux release 7.6.1810 (Core)docker 版本&#xff1a;docker-26.1.0.tgz 官网下载地址…

【RAG 论文】Chain-of-Note:为 RAG 引入 CoT 让模型生成阅读笔记来提高面对噪音文档和未知场景的鲁棒性

论文&#xff1a;Chain-of-Note: Enhancing Robustness in Retrieval-Augmented Language Models ⭐⭐⭐ Tencent AI Lab, arXiv:2311.09210 文章目录 一、论文速读二、实现的细节2.1 Note Design2.2 Data Collection2.3 Model Training 三、实验结果3.1 QA Performance3.2 对 …

虚拟机VMware下ROS Neotic(Ubuntu 20.04)下安装OpenCV

一、ROS安装 ROS的官方安装步骤&#xff1a; 1、noetic / Ubuntu 20.04 &#xff1a; http://wiki.ros.org/noetic/Installation/Ubuntu 2、melodic / Ubuntu 18.04&#xff1a; http://wiki.ros.org/melodic/Installation/Ubuntu 3、kinetic / Ubuntu 16.04&#xff1a; http:…