Java中Set集合是如何实现添加元素保证不重复的?
点击上方蓝色“程序猿DD”,选择“设为星标”
回复“资源”获取独家整理的学习资料!
来源 | 公众号「武培轩」
Java中Set集合是如何实现添加元素保证不重复的?
Set集合是一个无序的不可以重复的集合。今天来看一下为什么不可以重复。
Set是一个接口,最常用的实现类就是HashSet,今天我们就拿HashSet为例。
先简单介绍一下HashSet类
HashSet类实现了Set接口, 其底层其实是包装了一个HashMap去实现的。HashSet采用HashCode算法来存取集合中的元素,因此具有比较好的读取和查找性能。
先看下HashSet的几个构造方法。
// 默认构造函数 底层创建一个HashMappublic HashSet() {// 调用HashMap的默认构造函数,创建mapmap = new HashMap<E,Object>();}// 带集合的构造函数public HashSet(Collection<? extends E> c) {// 创建map。map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));// 将集合(c)中的全部元素添加到HashSet中addAll(c);}// 指定HashSet初始容量和加载因子的构造函数public HashSet(int initialCapacity, float loadFactor) {map = new HashMap<E,Object>(initialCapacity, loadFactor);}// 指定HashSet初始容量的构造函数public HashSet(int initialCapacity) {map = new HashMap<E,Object>(initialCapacity);}HashSet(int initialCapacity, float loadFactor, boolean dummy) {map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);}
再来看HashSet中的声明。
private transient HashMap<E,Object> map;// 用来匹配Map中后面的对象的一个虚拟值
private static final Object PRESENT = new Object();
接下来就是我们的重点HashSet的add()方法,贴上源码。
/*** 将元素e添加到HashSet中,也就是将元素e作为Key放入HashMap中** @param e 要添加到HashSet中的元素* @return true 如果不包含该元素*/public boolean add(E e) {return map.put(e, PRESENT)==null;}
从源码我们可以看出HashSet的add()方法又调用了HashMap中的put()方法,那我们再跳转到HashMap中的put()方法中。
public V put(K key, V value) {// 倒数第二个参数false:表示允许旧值替换// 最后一个参数true:表示HashMap不处于创建模式return putVal(hash(key), key, value, false, true);}
HashMap中的put()方法又调用了putVal()方法来实现功能,再看putVal()的源码。
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K, V>[] tab;Node<K, V> p;int n, i;//如果哈希表为空,调用resize()创建一个哈希表,并用变量n记录哈希表长度if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;/*** 如果指定参数hash在表中没有对应的桶,即为没有碰撞* Hash函数,(n - 1) & hash 计算key将被放置的槽位* (n - 1) & hash 本质上是hash % n,位运算更快*/if ((p = tab[i = (n - 1) & hash]) == null)//直接将键值对插入到map中即可tab[i] = newNode(hash, key, value, null);else {// 桶中已经存在元素Node<K, V> e;K k;// 比较桶中第一个元素(数组中的结点)的hash值相等,key相等if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))// 将第一个元素赋值给e,用e来记录e = p;// 当前桶中无该键值对,且桶是红黑树结构,按照红黑树结构插入else if (p instanceof TreeNode)e = ((TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);// 当前桶中无该键值对,且桶是链表结构,按照链表结构插入到尾部else {for (int binCount = 0; ; ++binCount) {// 遍历到链表尾部if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);// 检查链表长度是否达到阈值,达到将该槽位节点组织形式转为红黑树if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}// 链表节点的<key, value>与put操作<key, value>相同时,不做重复操作,跳出循环if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}// 找到或新建一个key和hashCode与插入元素相等的键值对,进行put操作if (e != null) { // existing mapping for key// 记录e的valueV oldValue = e.value;/*** onlyIfAbsent为false或旧值为null时,允许替换旧值* 否则无需替换*/if (!onlyIfAbsent || oldValue == null)e.value = value;// 访问后回调afterNodeAccess(e);// 返回旧值return oldValue;}}// 更新结构化修改信息++modCount;// 键值对数目超过阈值时,进行rehashif (++size > threshold)resize();// 插入后回调afterNodeInsertion(evict);return null;}
从源码中,我们可以看出将一个key-value对放入HashMap中时,首先根据key的hashCode()返回值决定该Entry的存储位置,如果两个key的hash值相同,那么它们的存储位置相同。如果这个两个key的equals比较返回true。那么新添加的Entry的value会覆盖原来的Entry的value,key不会覆盖。且HashSet中add()中 map.put(e, PRESENT)==null 为false,HashSet添加元素失败。因此,如果向HashSet中添加一个已经存在的元素,新添加的集合元素不会覆盖原来已有的集合元素。
往期推荐
百度开源的 71 个项目,看看你用过几个?
Spring Boot + Dataway :接口不用写,配配就出来?
用Java写一个植物大战僵尸简易版!
GitHub发布重大更新,关系到所有程序员!
GitHub 热榜:文字识别神器,超轻量级中文 OCR!
听说你想从事中间件开发?
扫码登录是如何实现的?
扫一扫,关注我
一起学习,一起进步
Java中Set集合是如何实现添加元素保证不重复的?相关推荐
- 万字长文深入理解java中的集合-附PDF下载
文章目录 1. 前言 2. List 2.1 fail-safe fail-fast知多少 2.1.1 Fail-fast Iterator 2.1.2 Fail-fast 的原理 2.1.3 Fai ...
- java中的集合框架_JAVA中的集合框架(上)List
第一节 JAVA中的集合框架概述 集合的概念,现实生活中:很多事物凑在一起就是一个集合:数学中的集合:具有相同属性事物的总体:JAVA中的集合:是一种工具类,就像是容器,储存任意数量的具有共同属性的对 ...
- java中各种集合的用法和比较
一,java中各种集合的关系图 Collection 接口的接口 对象的集合 ├ List 子接口 按进入先后有序保存 可重复 │├ L ...
- java 中的集合_JAVA中的集合
JAVA中集合,是java中的基础概念,今天接着跟讲课准备课件的机会,重新整理一下关于JAVA中的集合的概念. 集合的概念 java中的集合类是用来存放对象的 集合相当于一个容器,里面包容着一组对象- ...
- Java中的集合List - 入门篇
前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的集合List - 入门篇>,希望对大家有帮助,谢谢 简介 说实话,Java中的集合有很多种,但是这里作为入门级别,先简单介绍第一种 ...
- Java中的集合多线程的理解
Java中的集合 1.List.Set和Queue [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DwpgIu9t-1587300088779)(file:///C:\ ...
- Java中的集合浅析
java中的集合就像是一个容器一样,专门用来存储java对象的引用,这些对象可以是任意的数据类型并且长度可变,集合类位于java.util包中. java集合按照其存储结构可以分为两大类,一个是单列集 ...
- Java中List集合介绍(炒鸡详细呦)
Java中List集合介绍 文章目录 Java中List集合介绍 1,Java集合介绍 2,List介绍 2.1 ArrayList集合 2.2 LinkedList集合 3,List常用方法 3.1 ...
- java去重复的集合_如何去除Java中List集合中的重复数据
1.循环list中的所有元素然后删除重复 public class duplicatRemoval { public static List removeDuplicate(List list){ f ...
最新文章
- SICP 习题 (2.7) 解题总结 : 定义区间数据结构
- 元宇宙教不会区块链赚钱
- C++内部类访问外部类
- Jzoj5317 Func
- PyTorch Softmax
- mysql cluster 用户_mysql cluster统一用户权限
- 【Machine Learning 一】监督学习与无监督学习
- 为什么很多公司只给博士发安家费,却不给研究生和本科生发?
- 使用 sync.ErrGroup 实现并发搜索文件
- android学习中常见问题集锦
- paip.提高效率---集合的存取括号方式 uapi java python php js 的实现比较
- java多线程读取分割的文件_java多线程批量读取文件(二)--读写分离
- 方舟生存进化掉落物代码
- CentOS7或7以上,无iptable解决方法
- PS 宏使用方法记录
- sof与NIOS II的elf固件合并生成jic文件
- 插入式CAN总线隔离适配器LCAN-Opto在高空作业平台上隔离干扰、调理信号的应用案例介绍
- php代码审计靶场,RIPS --代码审计靶场(第一关)-华盟网
- rewind() 函数
- 判断电脑是否安装WPS