Java集合——Set接口学习总结

news/2024/5/5 19:15:43/文章来源:https://blog.csdn.net/qq_36445854/article/details/130033355

一、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部分整体结构图

在这里插入图片描述

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

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

相关文章

Spark 对hadoopnamenode-log文件进行数据清洗并存入mysql数据库

一.查找需要清洗的文件 1.1查看hadoopnamenode-log文件位置 1.2 开启Hadoop集群和Hive元数据、Hive远程连接 具体如何开启可以看我之前的文章&#xff1a;(10条消息) SparkSQL-liunx系统Spark连接Hive_难以言喻wyy的博客-CSDN博客 1.3 将这个文件传入到hdfs中&#xff1a; hd…

windows系统管理_windows server 2016 用户管理

用户账户的概述 **计算机用户账户&#xff1a;**由将用户定义到某一系统的所有信息组成的记录,账户为用户或计算机提供安 全凭证&#xff0c;包括用户名和用户登陆所需要的密码&#xff0c;以及用户使用以便用户和计算机能够登录到网络并 访问域资源的权利和权限。不同的身份拥…

【Obsidian】基础使用手册(包括如何将Obsidian页面设置为中文)

&#x1f497; 未来的游戏开发程序媛&#xff0c;现在的努力学习菜鸡 &#x1f4a6;本专栏是我关于工具类软件的笔记 &#x1f236;本篇是Obsidian的基础使用 Obsidian的基础使用将页面设置为中文常用的默认快捷键常用的格式标题代码块表格字体样式列表任务列表官方下载地址&am…

【音视频第11天】GCC论文阅读(2)

A Google Congestion Control Algorithm for Real-Time Communication draft-alvestrand-rmcat-congestion-03论文理解 看中文的GCC算法一脸懵。看一看英文版的&#xff0c;找一找感觉。 目录Abstract1. Introduction1.1 Mathematical notation conventions2. System model3.Fe…

获取淘宝商品分类详情API,抓取淘宝全品类目API接口分享(代码展示、参数说明)

商品分类技巧 淘宝店铺分类怎么设置&#xff1f;我们登录卖家账号的时候&#xff0c;我们看到自己的商品&#xff0c;会想要给商品进行分类&#xff0c;一个好的分类可以帮助提高商品的曝光率。那么在给商品分类前&#xff0c;如果您毫无头绪&#xff0c;以下几点可以给您带来…

车载网络 - Autosar网络管理 - 网络管理简介

一、什么是CAN网络管理及它的作用 现在的车辆是由大量的ECU节点组成的&#xff0c;为了能使各ECU能够正确并及时地进行CAN通信&#xff0c;需要有一套机制来统一协调总线上各节点的休眠唤醒&#xff0c;这套机制就是CAN网络管理&#xff08;NM&#xff09;。 网络管理的目的是保…

【算法题解】24. 模拟机器人行走

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

WPF mvvm框架Stylet使用教程-基础用法

Stylet框架基础用法 安装Nuget包 在“管理Nuget程序包”中搜索Stylet&#xff0c;查看Stylet包支持的net版本&#xff0c;然后选择第二个Stylet.Start包进行安装&#xff0c;该包会自动安装stylet并且生成基本的配置 注意事项&#xff1a;安装时要把需要安装的程序设为启动项…

PyCharm2021安装教程

PyCharm是一种Python IDE&#xff0c;带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具&#xff0c;比如调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制。此外&#xff0c;该IDE提供了一些高级功能&#xff0c;以用于支持Djang…

IntersectionObserver与无限滚动加载

学习链接 IntersectionObserver MDN Api IntersectionObserver API详解 Intersection observer 的概念和用法 过去&#xff0c;要检测一个元素是否可见或者两个元素是否相交并不容易&#xff0c;比如实现图片懒加载、内容无限滚动等功能时&#xff0c;都需要通过​getBound…

[Date structure]时间/空间复杂度

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;数据结构。数据结构专栏主要是在讲解原理的基础上拿Java实现&#xff0c;有时候有C/C代码。 ⭐如果觉得文章写的…

linux文件类型和根目录结构

目录 一、Linux文件类型 二、Linux系统的目录结构 1. FHS 2. 路径以及工作目录 &#xff08;1&#xff09;路径 &#xff08;2&#xff09;工作目录 一、Linux文件类型 使用ls -l命令查看到的第一个字符文件类型说明-普通文件类似于Windows的记事本d目录文件类似于Windo…

[NOIP2000 提高组] 进制转换

[NOIP2000 提高组] 进制转换 题目描述 我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置为指数,以 10为底数的幂之和的形式。例如 123 可表示为 10^22*10^13*10^0 这样的形式。 与之相似的&#xff0c;对二进制数来说&#xff0c;也可表示成…

WordPress添加阿里云OSS对象云储存配置教程

背景&#xff1a;随着页面文章增多&#xff0c;内置图片存储拖连网站响应速度&#xff0c;这里对我来说主要是想提升速度 目的&#xff1a;使用第三方云存储作为图片外存储(图床)&#xff0c;这样处理可以为服务器节省很多磁盘空间&#xff0c;在网站搬家的时候减少文件迁移的工…

2023TYUT移动应用软件开发程序设计和填空

目录 程序设计 程序设计1&#xff1a;根据要求设计UI,补充相应布局文件&#xff0c;即.xml文件 程序设计2&#xff1a;根据要求,补充Activity.java文件 程序填空 说明&#xff1a; 程序设计 程序设计1&#xff1a;根据要求设计UI,补充相应布局文件&#xff0c;即.xml文件…

安装Nginx——docker安装

使用docker安装Nginx 1.开启docker systemctl start docker docker search nginx[rootlocalhost ~]# systemctl start docker //开启docker [rootlocalhost ~]# docker search nginx //搜素镜像 2. docker pull nginxdocker imagesdocker run -…

【ROS】基于WIFI网络实现图像消息跨机实时传输

【开发背景】 研究机器人目标检测算法的时候&#xff0c;常常需要把推理图像实时展示出来&#xff0c;以供观摩。而ROS1提供的跨机通信方法&#xff0c;要么是配置单Master&#xff0c;要么是配置多Master&#xff1b;一方面配置麻烦&#xff0c;另一方面传输效率低下&#xf…

SQL select总结(基于选课系统)

表详情&#xff1a; 学生表&#xff1a; 学院表&#xff1a; 学生选课记录表&#xff1a; 课程表&#xff1a; 教师表&#xff1a; 查询&#xff1a; 1. 查全表 -- 01. 查询所有学生的所有信息 -- 方法一&#xff1a;会更复杂&#xff0c;进行了两次查询&#xff0c;第一…

基于灵动微SPIN系列开发的水泵方案介绍 以 MM32SPIN040C/MM32SPIN560C为主控

水泵是输送液体或使液体增压的机械。它将原动机的机械能或其他外部能量传送给液体&#xff0c;使液体能量增加&#xff0c;主要用来输送液体包括水、油、酸碱液、乳化液、悬乳液和液态金属等。 水泵以 MM32SPIN040C/MM32SPIN560C为主控。 水泵方案 MCU: MM32SPIN系列 1.输入…

【JavaWeb】后端(Maven+SpringBoot+HTTP+Tomcat)

目录一、Maven1.什么是Maven?2.Maven的作用?3.介绍4.安装5.IDEA集成Maven6.IDEA创建Maven项目7.IDEA导入Maven项目8.依赖配置9.依赖传递10.依赖范围11.生命周期二、SpringBoot1.Spring2.SpringBoot3.SpringBootWeb快速入门二、HTTP1.HTTP-概述2.HTTP-请求协议3.HTTP-响应协议…