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语言进阶系列,本专栏主要内容为数据的存储、指针的进阶、字符串和内存函数的介绍、自定义类型结构、动态内存管理、文件操作等࿰…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...

yaml读取写入常见错误 (‘cannot represent an object‘, 117)
错误一:yaml.representer.RepresenterError: (‘cannot represent an object’, 117) 出现这个问题一直没找到原因,后面把yaml.safe_dump直接替换成yaml.dump,确实能保存,但出现乱码: 放弃yaml.dump,又切…...

从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...

可视化预警系统:如何实现生产风险的实时监控?
在生产环境中,风险无处不在,而传统的监控方式往往只能事后补救,难以做到提前预警。但如今,可视化预警系统正在改变这一切!它能够实时收集和分析生产数据,通过直观的图表和警报,让管理者第一时间…...