Java进阶(Set)——面试时Set常见问题解读 结合源码分析

前言
List、Set、HashMap作为Java中常用的集合,需要深入认识其原理和特性。
本篇博客介绍常见的关于Java中Set集合的面试问题,结合源码分析题目背后的知识点。
关于List的博客文章如下:
- Java进阶(List)——面试时List常见问题解读 & 结合源码分析
关于的Set的博客文章如下:
- Java进阶(Set)——面试时Set常见问题解读 & 结合源码分析
关于HaseMap的博客文章如下:
- Java进阶(HashMap)——面试时HashMap常见问题解读 & 结合源码分析
- Java进阶(ConcurrentHashMap)——面试时ConcurrentHashMap常见问题解读 & 结合源码分析 & 多线程CAS比较并交换 初识
其他相关的Set的文章如下:
- Java学数据结构(3)——树Tree & B树 & 红黑树 & Java标准库中的集合Set与映射Map & 使用多个映射Map的案例
目录
- 前言
- 引出
- 1. 描述一下HashSet的底层原理?
- 构造方法
- add方法
- 2. map.put方法,静态常量PRESENT
- 3. map.remove key方法,PRESENT进行比较
- 4. HashSet的去重原理?
- 5. 如何选择HashSet 或 TreeSet?
- 6. 如何得到一个线程安全的Set集合?
- 总结
引出
1.特点:无序,去重,非线程安全;
2.底层:HashMap的Key值实现的;
3.map.put方法,静态常量PRESENT,新值替换旧值;
4.map.remove key方法,如果KEY不存在时,则返回的是null,如果KEY存在时,返回的就是e.value,即PRESENT,返回true成功,返回false不成功;
5.去重原理:先判断hash值,再通过==或者equals判断,整体如果返回true,则为重复元素;
6.无序的则采用HashSet ,有序的则采用TreeSet;
7.线程安全的set:Collections.synchronizedSet(new HashSet<>());
1. 描述一下HashSet的底层原理?
- HashSet的特点:无序,去重,非线程安全;
- HashSet 底层是用HashMap的Key值实现的,也有上面的3大特征;
构造方法
无参和代参构造方法都会初始化这个HashMap
无参的构造方法,调用了HashMap方法

有参的构造方法也是,调用了HashMap方法


add方法

add方法中可以看出调用HashMap的put方法,key为放入元素,值为常量PRESENT

2. map.put方法,静态常量PRESENT
既然hashset基于hashmap实现,你说一下 hashset的add方法中,为什么要在map.put的val上放上一个Object类型的静态常量PRESENT?

HashSet底层调用了map的put方法,传入了存储的对象和PRESENT常量,那我们进入put方法继续查看

put方法内调用了putVal方法,PRESENT常量为形参value,继续进入查看

if (e != null) { // existing mapping for key//把旧数据存储到oldValueV oldValue = e.value;//如果说存储的位置上已经有元素了if (!onlyIfAbsent || oldValue == null)//新元素会替代旧元素 新KEY替代KEYe.value = value;afterNodeAccess(e);//返回旧元素数据return oldValue;}++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);//如果说上面的if结构没有执行,那么就说明这个位置上没有元素,则新增成功,返回nullreturn null;


public boolean add(E e) {//上面的方法返回值决定了HashSet的add方法到底返回true还是falsereturn map.put(e, PRESENT)==null;}
- 此方法内部明确箭头标处的原理,value就是PRESENT,如果进入这个if结构,则说明这个位置上已经存在该key,则会用value替换之前的旧值,然后返回旧值oldValue,否则会返回null;
- 至此,我们可以看出此方法的返回值是PRESENT或者是null,如果为PRESENT则说明KEY已存在,则add方法就会返回false(此处元素put还是成功的,只是新值替换旧值),返回null则add返回true,此KEY不存在,代表存储新的KEY-VALUE;
3. map.remove key方法,PRESENT进行比较
既然hashset基于hashmap实现,你说一下 hashset的remove方法中,为什么要在map.remove key 完了之后要和PRESENT进行一个等值比较呢?


- 从HashMap的remove方法中可以看出,方法返回的是e.value或者null,与add方法中的原理一起联想,则会明白,如果KEY不存在时,则返回的是null,如果KEY存在时,返回的就是e.value,即PRESENT;
- 所以在HashSet在判断此返回值==PRESENT,如果相等则返回true,说明此KEY是存在的,删除成功返回true,如果返回值是null,那么null=PRESENT则返回的肯定是false,那么代表此KEY不存在,删除自然不成功,返回false;

public V remove(Object key) {Node<K,V> e;//判断了一下,如果removeNode删除得到的是null,说明此KEY不存在,方法返回nullreturn (e = removeNode(hash(key), key, null, false, true)) == null ?//否则返回e.value 就是 PRESENTnull : e.value;}
public boolean remove(Object o) {//因为HashMap删除成功返回的是PRESENT , ==PRESENT 则结果为true 代表删除成功//否则返回的是null , 返回false 删除失败return map.remove(o)==PRESENT;}
4. HashSet的去重原理?

- HashMap中putVal方法中有这么一段代码判断,去重原理在于hashcode的判断和equals方法的判断
- 先判断hash值,再通过==或者equals判断,整体如果返回true,则为重复元素
5. 如何选择HashSet 或 TreeSet?
无序的则采用HashSet ,有序的则采用TreeSet
6. 如何得到一个线程安全的Set集合?
Set datas = Collections.synchronizedSet(new HashSet<>());

总结
1.特点:无序,去重,非线程安全;
2.底层:HashMap的Key值实现的;
3.map.put方法,静态常量PRESENT,新值替换旧值;
4.map.remove key方法,如果KEY不存在时,则返回的是null,如果KEY存在时,返回的就是e.value,即PRESENT,返回true成功,返回false不成功;
5.去重原理:先判断hash值,再通过==或者equals判断,整体如果返回true,则为重复元素;
6.无序的则采用HashSet ,有序的则采用TreeSet;
7.线程安全的set:Collections.synchronizedSet(new HashSet<>());
相关文章:
Java进阶(Set)——面试时Set常见问题解读 结合源码分析
前言 List、Set、HashMap作为Java中常用的集合,需要深入认识其原理和特性。 本篇博客介绍常见的关于Java中Set集合的面试问题,结合源码分析题目背后的知识点。 关于List的博客文章如下: Java进阶(List)——面试时L…...
【强化学习】12 —— 策略梯度(REINFORCE )
文章目录 前言策略梯度基于策略的强化学习的优缺点Example:Aliased Gridworld策略目标函数策略优化策略梯度利用有限差分计算策略梯度得分函数和似然比策略梯度定理蒙特卡洛策略梯度(Monte-Carlo Policy Gradient)Puck World Example Softmax随机策略 代…...
Kubernetes Taint(污点) 和 Toleration(容忍)
Author:rab 目录 前言一、Taint(污点)1.1 概述1.2 查看节点 Taint1.3 标记节点 Taint1.4 删除节点 Taint 二、Toleration(容忍) 前言 Kubernetes 中的污点(Taint)和容忍(Toleration…...
使用cv::FileStorage时出错 Can‘t open file: yaml‘ in read mode
1. 使用说明 在做的一个c工程项目,想加一个配置文件,我发现主要有两种主流的方式, (1)opencv有cv::FileStorage这样的一个函数可以使用。 (2)也可以使用cpp-yaml GitHub - jbeder/yaml-cpp: …...
代码之困:那些让你苦笑不得的bug
在编写代码的过程中,我们常常会遇到各种各样的bug。有的时候,我们花费了大量的时间和精力去寻找问题的根源,但却找不到任何线索。然而,令人哭笑不得的是,有时候这些问题的解决方案却是如此简单,以至于我们不…...
【C语言初学者周冲刺计划】2.2用选择法对10个整数从小到大排序
目录 1解题思路: 2代码如下: 3运行结果: 4总结: 1解题思路: 首先利用一维数组和循环语句输入10个整数,然后利用双循环的嵌套进行比较大小,最后输出结果; 2代码如下: #include&…...
c++系列——智能指针
1.智能指针的使用及原理 1.1 RAII RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内 存、文件句柄、网络连接、互斥量等等)的简单技术。 在对象构造时获取资源,接着控制对资…...
力扣日记10.30-【栈与队列篇】滑动窗口最大值
力扣日记:【栈与队列篇】滑动窗口最大值 日期:2023.10.30 参考:代码随想录、力扣 239. 滑动窗口最大值 题目描述 难度:困难 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只…...
docker与宿主机共享内存通信
docker与宿主机共享内存通信 docker中的进程要与宿主机使用共享内存通信,需要在启动容器的时候指定“–ipchost”选项。然后再编写相应的共享内存的程序,一个跑在宿主机上,另一个跑在docker上面。 宿主机程序准备 shm_data.h #ifndef _SH…...
A股风格因子看板 (2023.10 第13期)
该因子看板跟踪A股风格因子,该因子主要解释沪深两市的市场收益、刻画市场风格趋势的系列风格因子,用以分析市场风格切换、组合风格暴露等。 今日为该因子跟踪第13期,指数组合数据截止日2023-09-30,要点如下 近1年A股风格因子检验统…...
ORB-SLAM3算法2之EuRoc、TUM和KITTI开源数据集运行ORB-SLAM3生成轨迹并用evo工具评估轨迹
文章目录 0 引言1 数据和真值1.1 TUM1.2 EuRoc1.3 KITTI2 ORB-SLAM3的EuRoc示例2.1 纯单目的示例2.2 纯单目的轨迹评估2.3 纯双目的示例2.4 纯双目的轨迹评估2.5 单目和IMU的示例2.6 单目和IMU的轨迹评估2.7 双目和IMU的示例2.8 双目和IMU的轨迹评估2.9 前四种的评估结果对比3 …...
【蓝桥杯选拔赛真题07】C++小球自由落体 青少年组蓝桥杯C++选拔赛真题 STEMA比赛真题解析
目录 C/C++小球自由落体 一、题目要求 1、编程实现 2、输入输出 二、算法分析...
期中考成绩一键私发
作为一名教师,期中考试后最繁忙的事情之一就是发布成绩。每个学生都希望尽快知道自己的成绩,而作为老师,我们需要一种更高效、更方便的方式来完成这项任务。今天,我就来给大家介绍一种成绩查询系统,让我们一起告别繁琐…...
idea中Run/Debug Python项目报错 Argument for @NotNull parameter ‘module‘ of ...
idea中Run/Debug Python项目报错 Argument for NotNull parameter module of ... idea中运行Python项目main.py时报错: Error running main: Argument for NotNull parameter module of com/intellij/openapi/roots/ModuleRootManager.getInstance must not be nu…...
计算机网络第3章-TCP协议(2)
TCP拥塞控制 TCP拥塞控制的三种方式: 慢启动、拥塞避免、快速恢复 慢启动 当一条TCP连接开始时,cwnd的值是一个很小的MSS值,这使得初始发送速率大约为MSS/RTT。 在慢启动状态,cwnd的值以1个MSS开始并且每当传输的报文段首次被…...
SQL注入——二次注入漏洞
文章目录 SQL注入——二次注入漏洞1. 二次注入原理2. 二次注入需要具备的两个条件3. 二次注入实例4. 总结 SQL注入——二次注入漏洞 1. 二次注入原理 在第一次插入恶意数据的时候,只是对其中的特殊字符进行了转义,在写入数据库的时候还是原来的字符&am…...
【c++|opencv】二、灰度变换和空间滤波---1.灰度变换、对数变换、伽马变换
every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 灰度变换、对数变换、伽马变换 1. 灰度变换 #include <iostream> #include <opencv2/opencv.hpp>using namespace std; using namespace c…...
【vue3】子传父-事件总线-mitt(子组件派发事件,父组件接收事件和传递的参数)
安装库:cnpm install mitt 封装 eventbus.ts: src->utils->eventbus.ts //eventbus.tsimport mitt from mittconst emitter mitt()export default emitter使用 B2.vue: //B2.vue <template><div class"aa">…...
【杂记】java 大集合进行拆分
日常中需要对一个大的集合进行拆分成多个小集合,其主要思路为: 设置需要拆分多少个小集合 A大集合里面有多少条数据 B计算出每个集合里面有多个条数据 CB/A计算出看是否存在余数 DB%A采用集合(List.subList())的方法对大集合进行拆分,循环A变进行集合拆…...
select...for update 锁表了?
在MySQL中,事务A中使用select...for update where id1锁住了,某一条数据,事务还没提交,此时,事务B中去用select ... where id1查询那条数据,会阻塞等待吗? select...for update在MySQL中&#…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
Linux中《基础IO》详细介绍
目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改,实现简单cat命令 输出信息到显示器,你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...
Sklearn 机器学习 缺失值处理 获取填充失值的统计值
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...
