Java集合——Set接口学习总结
一、HashSet实现类
1.常用方法
增加:add(E e)删除:remove(Object o)、clear()修改:查看:iterator()判断:contains(Object o)、isEmpty()常用遍历方式:
Set<String> set = new HashSet<String>();set.add("aa");set.add("bb");set.add("cc");//1.迭代器打印Iterator iterator = set.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}//2.增强forfor (String s : set) {System.out.println(s);}//3.直接输出System.out.println(set);
2.JDK1.8(jdk1.8.0_361)源码下(简要)
public class HashSet<E> extends AbstractSet<E>implements Set<E>, Cloneable, java.io.Serializable
{//成员变量private transient HashMap<E,Object> map; //HashSet存储主体private static final Object PRESENT = new Object();//构造器,可以看出来底层是用的HashMap来实现的,这块需要对HashMap源码熟悉//创建出来的时候,数组是null,只有调用add方法才会进行数组初始化//Constructs a new, empty set; the backing HashMap instance has default initial capacity (16) and load factor (0.75).//构造一个具有默认初始容量(16)和负载因子(0.75)的新的,空的链接散列集public HashSet() {map = new HashMap<>();}public HashSet(Collection<? extends E> c) {map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));addAll(c);}public HashSet(int initialCapacity, float loadFactor) {map = new HashMap<>(initialCapacity, loadFactor);}public HashSet(int initialCapacity) {map = new HashMap<>(initialCapacity);}//这个就是LinkedHashSet创建时会调用的构造器HashSet(int initialCapacity, float loadFactor, boolean dummy) {map = new LinkedHashMap<>(initialCapacity, loadFactor);}//添加public boolean add(E e) {return map.put(e, PRESENT)==null;}//删除public boolean remove(Object o) {return map.remove(o)==PRESENT;}public void clear() {map.clear();}}
3.HashSet原理图
public class TestSet {public static void main(String[] args) {HashSet<Student> hs = new HashSet<>();hs.add(new Student(19,"lili"));hs.add(new Student(20,"lulu"));hs.add(new Student(18,"feifei"));hs.add(new Student(19,"lili"));hs.add(new Student(10,"nana"));hs.add(new Student(10,"nana"));System.out.println(hs.size());//并没有出现唯一数据的情况,为什么呢?//原因是没有重写Student类的hashcode和equals方法,无法判断是否同一个数据System.out.println(hs);HashSet<Integer> hs01 = new HashSet<>();System.out.println(hs01.add(19));//truehs01.add(6);hs01.add(17);hs01.add(11);hs01.add(3);System.out.println(hs01.add(19));//false 这个19没有放入到集合中System.out.println(hs01.size());//唯一,无序System.out.println(hs01);}
}class Student {int age;String name;public Student(int age, String name) {this.age = age;this.name = name;}
}
运行结果
如果不了解HashMap底层的话,可以结合以下图片进行说明:
总结:HashSet底层是使用的HashMap类来进行的存储,因此底层存储是通过数组+链表方式实现数据存储的。
HashSet的无序、唯一是基于HashMap(key,PRESENT)来实现的,所以对于基础数据类型、String类型是无序唯一的,但是对于没有重写过hashcode方法和equals方法的引用类来说不是唯一的。这块理解需要解锁前置技能- HashMap。
二、LinkedHashSet实现类
1.常用方法
LinkedHashSet是HashSet的子类,因此方法使用跟HashSet相同
增加:add(E e)删除:remove(Object o)、clear()修改:查看:iterator()判断:contains(Object o)、isEmpty()常用遍历方式:...
2.JDK1.8(jdk1.8.0_361)源码
public class LinkedHashSet<E> extends HashSet<E>implements Set<E>, Cloneable, java.io.Serializable {//调用父类HashSet的构造方法,构造一个具有默认初始容量(16)和负载因子(0.75)的新的,空的链接散列集。public LinkedHashSet() {super(16, .75f, true);}public LinkedHashSet(int initialCapacity) {super(initialCapacity, .75f, true);}public LinkedHashSet(Collection<? extends E> c) {super(Math.max(2*c.size(), 11), .75f, true);addAll(c);}public LinkedHashSet(int initialCapacity, float loadFactor) {super(initialCapacity, loadFactor, true);}public Spliterator<E> spliterator() {return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);}
}
总结,源码非常简短,从调用的构造方法上是可以看出,实际LinkedHashSet底层是使用的LinkedHashMap进行存储。其实就是在HashSet的基础上,多了一个总的链表,这个总链表将放入的元素串在一起,方便有序的遍历,(可以看到LinkedHashMap.Entry 继承自HashMap.Node 除了Node 本身有的几个属性外,额外增加了before after 用于指向前一个Entry 后一个Entry。也就是说,元素之间维持着一条总的链表数据结构。)。这块理解需要有有前置技能- LinkedHashMap和HashMap。
三、比较器(TreeSet理解前置技能)
【1】以int类型为案例:
比较的思路:将比较的数据做差,然后返回一个int类型的数据,将这个int类型的数值 按照 =0 >0 <0
int a = 10;int b = 20;System.out.println(a-b); // -10 通过=0 >0 <0来判断
【2】比较String类型数据:
String类实现了Comparable接口,这个接口中有一个抽象方法compareTo,String类中重写这个方法即可
String a = "A";String b = "B";System.out.println(a.compareTo(b)); //-1,String比较器源码如下
【3】比较double类型数据:
double a = 9.6;double b = 9.3;System.out.println(((Double) a).compareTo((Double) b)); //1
【4】比较自定义的数据类型:
(1)内部比较器:
通过实现Comparable接口实现,缺点是只有一个比较方法,不能实现多个不同属性的比较方法
public class Student implements Comparable<Student>{private int age;private double height;private String name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public double getHeight() {return height;}public void setHeight(double height) {this.height = height;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Student(int age, double height, String name) {this.age = age;this.height = height;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", height=" + height +", name='" + name + '\'' +'}';}@Overridepublic int compareTo(Student o) {//按照年龄进行比较:/*return this.getAge() - o.getAge();*///按照身高比较/*return ((Double)(this.getHeight())).compareTo((Double)(o.getHeight()));*///按照名字比较:return this.getName().compareTo(o.getName());}
}
public class TesBJ {public static void main(String[] args) {//比较两个学生:Student s1 = new Student(14,160.5,"alili");Student s2 = new Student(14,170.5,"bnana");System.out.println(s1.compareTo(s2)); //结果 -1}
}
(2)外部比较器:
import java.util.Comparator;public class Student{private int age;private double height;private String name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public double getHeight() {return height;}public void setHeight(double height) {this.height = height;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Student(int age, double height, String name) {this.age = age;this.height = height;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", height=" + height +", name='" + name + '\'' +'}';}
}
class BiJiao01 implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {//比较年龄:return o1.getAge()-o2.getAge();}
}
class BiJiao02 implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {//比较姓名:return o1.getName().compareTo(o2.getName());}
}
class BiJiao03 implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {//在年龄相同的情况下 比较身高 年龄不同比较年龄if((o1.getAge()-o2.getAge())==0){return ((Double)(o1.getHeight())).compareTo((Double)(o2.getHeight()));}else{//年龄不一样return o1.getAge()-o2.getAge();}}
}
【5】外部比较器和内部比较器 谁好?
答案:外部比较器,多态,扩展性好
理解完比较器后就能开始看TreeSet的源码了。
四、TreeSet实现类
1.常用方法
HashSet的子类,所以常用方法同HashSet
2.TreeSet使用
【1】存入Integer类型数据:(底层利用的是内部比较器)
特点:唯一,无序(没有按照输入顺序进行输出), 有序(按照升序进行遍历)
底层原理:二叉树(数据结构中的一个逻辑结构)
TreeSet底层的二叉树的遍历是按照升序的结果出现的,这个升序是靠中序遍历得到的(不熟悉的话得再看一下数据结构与算法):
【2】放入String类型数据:(底层实现类内部比较器)
【4】想放入自定义的Student类型的数据:
(1)利用内部比较器:
public class Student implements Comparable<Student> {private int age;private String name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}@Overridepublic int compareTo(Student o) {//按年龄排序return this.getAge()-o.getAge();}
}
少了一个,是因为比较器按照年龄进行比较,年龄相同的去除掉。TreeSet的add方法内部调用的TreeMap的put方法,详细解析需要看TreeMap源码中put方法中如何调用的比较器,以及根据比较器返回的结果>0 =0 <0做了什么操作,外部比较器同理。
(2)通过外部比较器:
import java.util.Comparator;public class Student{private int age;private String name;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}}
class BiJiao implements Comparator<Student>{@Overridepublic int compare(Student o1, Student o2) {return o1.getName().compareTo(o2.getName());}
}
3.JDK1.8(jdk1.8.0_361)源码下(简要)
简要拿出常用部分,其余方法可以自行看jdk1.8的文档,utools软件里面有
public class TreeSet<E> extends AbstractSet<E>implements NavigableSet<E>, Cloneable, java.io.Serializable
{//存储的数据就是在这里//NavigableMap<K,V>是接口,TreeMap<K,V>是这个接口的实现类private transient NavigableMap<E,Object> m;//虚拟固定的valueprivate static final Object PRESENT = new Object();//没有传参数时,构造器就是直接new TreeMap<E,Object>()再传给下一个构造器public TreeSet() {this(new TreeMap<E,Object>());}//没有修饰符,只能同包内使用TreeSet(NavigableMap<E,Object> m) {//接口=接口实现类,多态this.m = m;}//传入集合c所有元素添加进TreeSetpublic TreeSet(Collection<? extends E> c) {this();addAll(c);}//传入比较器,排序就是根据比较器规则进行处理。public TreeSet(Comparator<? super E> comparator) {this(new TreeMap<>(comparator));}//SortedSet<E>是接口,NavigableSet<E>接口继承自此接口//形参是接口,调用传实参是实现类,接口=接口实现类,多态public TreeSet(SortedSet<E> s) {this(s.comparator());addAll(s);}//升序迭代器public Iterator<E> iterator() {return m.navigableKeySet().iterator();}//降序迭代器public Iterator<E> descendingIterator() {return m.descendingKeySet().iterator();}//以降序返回一个新的 TreeSet 集合public NavigableSet<E> descendingSet() {return new TreeSet<>(m.descendingMap());}//元素个数public int size() {return m.size();}//是否为空public boolean isEmpty() {return m.isEmpty();}//是否含有元素opublic boolean contains(Object o) {return m.containsKey(o);}//添加public boolean add(E e) {return m.put(e, PRESENT)==null;}//删除public boolean remove(Object o) {return m.remove(o)==PRESENT;}//清空元素public void clear() {m.clear();}
}
总结:TreeSet部分源码较多,简化出了常用的方法。这块的理解需要了解TreeMap源码和树结构。
五.Collection部分整体结构图
相关文章:

Java集合——Set接口学习总结
一、HashSet实现类 1.常用方法 增加:add(E e)删除:remove(Object o)、clear()修改:查看:iterator()判断:contains(Object o)、isEmpty()常用遍历方式:Set<String> set new HashSet<String>()…...

2023最全的自动化测试入门基础知识(建议收藏)
1)首先,什么是自动化测试? 自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。通常,在设计了测试用例并通过评审之后,由测试人员根据测试用例中描述的过程一步步执行测试,得到实际结果与期望结果的比较。…...

【RabbitMQ】SpringBoot整合RabbitMQ、实现RabbitMQ五大工作模式(万字长文)
目录 一、准备 1、创建SpringBoot项目 2、添加配置信息 3、创建配置类 二、RabbitMQ的配置类里创建队列 三、RabbitMQ的配置类里创建交换机及绑定队列 四、SpringBoot整合RabbitMQ入门案例 1、生产者 2、消费者 四、SpringBoot里实现RabbitMQ五大工作模式 1、简单模式…...
ES6(函数扩展、数组扩展)
一、 函数扩展 1. 参数可以默认 ES5调用函数:如果给参数设置默认需要进行判断 ES6可以直接给参数设置默认 //ES5 function log(x, y) {//两种判断方法(传统分支判断、利用逻辑符)if (typeof y undefined) {y World;}//y y || World;cons…...

postman汉化教程
文章目录1. 下载对应版本的postman2.下载对应版本的汉化包2.1. github下载地址 : (9.12.2)2.2 百度网盘(9.12.2)3. 打开postman安装位置4. 压缩包解压到/resources目录下5. 重启postman即可汉化成中文了1. 下载对应版本的postman …...
java day8
第8章 数据结构8.1 超越数组8.2 java数据结构8.2.1 Iterator8.2.2 位组8.2.3 链表8.2.4 遍历数据结构8.2.5 堆栈8.1 超越数组 java类库的java.util包中有一组数据结构,它们让您能够更灵活地组织和操纵数据。 8.2 java数据结构 8.2.1 Iterator 接口Iterator提供了…...

口令暴力破解--Telnet协议暴力破解、数据库暴力破解与远程桌面暴力破解
Telnet协议暴力破解 Telnet Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。要开始一个telnet会话,必须输入用户名和密码来登录服务器。而一般服务器不会对用户名…...

[译]什么是SourceMap
原文链接: https://web.dev/source-maps/使用 SourceMap 来提升 web 调试体验。今天,我们要讨论的是 SourceMap,这是现代 Web 开发中至关重要的工具,它能够显著地简化调试工作。在本文中,我们将探讨 SourceMap 的基础知识…...
saga模式、Seata saga模式详解
文章目录 一、前言二、SAGA模式0、saga论文摘要1、什么是长事务?2、saga的组成3、saga的两种执行场景1)forward recovery2)backward recovery4、saga log5、saga协调(saga实现方式)1)SAGA - Choreography 策略2)SAGA - Orchestration 策略3)如何选择三、Seata saga模式…...
java开发工程师碰到技术难题怎么办?我来聊聊我的做法
最近公司遇到了一个技术难题。这一周基本上都在加班解决这个问题,头发也掉了不少,但问题还没有解决。我写这篇文章,主要是想看看看我文章的同学们是否有类似的经验或者是自己的一些想法。让我们看一下这个问题的一个具体情况。 我们的公司是…...

高比例可再生能源电力系统的调峰成本量化与分摊模型(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

Hive安装与操作
目录 环境 数据 实验步骤与结果 (1)环境启动 (2)Hive基本操作 环境 Hadoop集群开发环境、mysql、Hive环境 数据 course.txt、sc.txt、student.txt 实验步骤与结果 (1)环境启动 ①执行命令…...
oracle centos7安装Oracle12(附oracle所有版本安装包)
环境: centos 7 Oracle12c jdk1.8 一.配置环境 (1)安装依赖 yum -y install binutils.x86_64 compat-libcap1.x86_64 gcc.x86_64 gcc-c++.x86_64 glibc.i686 glibc.x86_64 glibc-devel.i686 glibc-devel.x86_64 ksh compat-libstdc++-33 libaio.i686 libaio.x86_64 libaio-…...

ESP32学习二-更新Python版本(Ubuntu)
一、简介 在一些场景里边,因为Python的版本过低,导致一些环境无法安装。这里来介绍以下,如何升级自己已安装的Python版本。例如如下情况: 二、实操 1.查看本地版本 python --version 2.添加源 sudo add-apt-repository ppa:jona…...

【19】核心易中期刊推荐——人工智能 | 遥感信息处理
🚀🚀🚀NEW!!!核心易中期刊推荐栏目来啦 ~ 📚🍀 核心期刊在国内的应用范围非常广,核心期刊发表论文是国内很多作者晋升的硬性要求,并且在国内属于顶尖论文发表,具有很高的学术价值。在中文核心目录体系中,权威代表有CSSCI、CSCD和北大核心。其中,中文期刊的数…...

MySQL运维10-MySQL数据的导入导出
文章目录0、概述1、mysqldump导出数据mysql导入数据1.1、使用mysqldump导出数据1.1.1、使用--tables导出指定表1.1.2、使用--tab选项将表定义文件和数据文件分开导出1.1.3、使用--fields-terminated-by选项定义数据分隔符1.1.4、使用--databases选项导出整个库或多个库1.1.5、使…...

全国计算机等级考试——二级JAVA完整大题题库【五十三道】
全国计算机等级考试二级 JAVA 题目内容 编写于2023.04.10 分为40道选择题和3道大题(大题是程序填空类型) 其中选择题只能进去做一次,一旦退出来则不可再进(注意!)。大题可以重复进入,重复做。…...

【算法题解】24. 模拟机器人行走
这是一道 中等难度 的题 https://leetcode.cn/problems/walking-robot-simulation/description/ 题目 机器人在一个无限大小的 XY 网格平面上行走,从点 (0, 0) 处开始出发,面向北方。该机器人可以接收以下三种类型的命令 commands : -2 &am…...

PyTorch 深度学习实战 |用 TensorFlow 训练神经网络
为了更好地理解神经网络如何解决现实世界中的问题,同时也为了熟悉 TensorFlow 的 API,本篇我们将会做一个有关如何训练神经网络的练习,并以此为例,训练一个类似的神经网络。我们即将看到的神经网络,是一个预训练好的用…...

【进阶C语言】静态版通讯录的实现(详细讲解+全部源码)
前言 📕作者简介:热爱跑步的恒川,正在学习C/C、Java、Python等。 📗本文收录于C语言进阶系列,本专栏主要内容为数据的存储、指针的进阶、字符串和内存函数的介绍、自定义类型结构、动态内存管理、文件操作等࿰…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...