当前位置: 首页 > news >正文

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.常用方法 增加&#xff1a;add(E e)删除&#xff1a;remove(Object o)、clear()修改&#xff1a;查看&#xff1a;iterator()判断&#xff1a;contains(Object o)、isEmpty()常用遍历方式&#xff1a;Set<String> set new HashSet<String>()…...

2023最全的自动化测试入门基础知识(建议收藏)

1)首先&#xff0c;什么是自动化测试&#xff1f; 自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。通常&#xff0c;在设计了测试用例并通过评审之后&#xff0c;由测试人员根据测试用例中描述的过程一步步执行测试&#xff0c;得到实际结果与期望结果的比较。…...

【RabbitMQ】SpringBoot整合RabbitMQ、实现RabbitMQ五大工作模式(万字长文)

目录 一、准备 1、创建SpringBoot项目 2、添加配置信息 3、创建配置类 二、RabbitMQ的配置类里创建队列 三、RabbitMQ的配置类里创建交换机及绑定队列 四、SpringBoot整合RabbitMQ入门案例 1、生产者 2、消费者 四、SpringBoot里实现RabbitMQ五大工作模式 1、简单模式…...

ES6(函数扩展、数组扩展)

一、 函数扩展 1. 参数可以默认 ES5调用函数&#xff1a;如果给参数设置默认需要进行判断 ES6可以直接给参数设置默认 //ES5 function log(x, y) {//两种判断方法&#xff08;传统分支判断、利用逻辑符&#xff09;if (typeof y undefined) {y World;}//y y || World;cons…...

postman汉化教程

文章目录1. 下载对应版本的postman2.下载对应版本的汉化包2.1. github下载地址 : &#xff08;9.12.2&#xff09;2.2 百度网盘&#xff08;9.12.2&#xff09;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包中有一组数据结构&#xff0c;它们让您能够更灵活地组织和操纵数据。 8.2 java数据结构 8.2.1 Iterator 接口Iterator提供了…...

口令暴力破解--Telnet协议暴力破解、数据库暴力破解与远程桌面暴力破解

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

[译]什么是SourceMap

原文链接: https://web.dev/source-maps/使用 SourceMap 来提升 web 调试体验。今天&#xff0c;我们要讨论的是 SourceMap&#xff0c;这是现代 Web 开发中至关重要的工具&#xff0c;它能够显著地简化调试工作。在本文中&#xff0c;我们将探讨 SourceMap 的基础知识&#xf…...

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开发工程师碰到技术难题怎么办?我来聊聊我的做法

最近公司遇到了一个技术难题。这一周基本上都在加班解决这个问题&#xff0c;头发也掉了不少&#xff0c;但问题还没有解决。我写这篇文章&#xff0c;主要是想看看看我文章的同学们是否有类似的经验或者是自己的一些想法。让我们看一下这个问题的一个具体情况。 我们的公司是…...

高比例可再生能源电力系统的调峰成本量化与分摊模型(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

Hive安装与操作

目录 环境 数据 实验步骤与结果 &#xff08;1&#xff09;环境启动 &#xff08;2&#xff09;Hive基本操作 环境 Hadoop集群开发环境、mysql、Hive环境 数据 course.txt、sc.txt、student.txt 实验步骤与结果 &#xff08;1&#xff09;环境启动 ①执行命令&#xf…...

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)

一、简介 在一些场景里边&#xff0c;因为Python的版本过低&#xff0c;导致一些环境无法安装。这里来介绍以下&#xff0c;如何升级自己已安装的Python版本。例如如下情况&#xff1a; 二、实操 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道大题&#xff08;大题是程序填空类型&#xff09; 其中选择题只能进去做一次&#xff0c;一旦退出来则不可再进&#xff08;注意&#xff01;&#xff09;。大题可以重复进入&#xff0c;重复做。…...

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

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

PyTorch 深度学习实战 |用 TensorFlow 训练神经网络

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

【进阶C语言】静态版通讯录的实现(详细讲解+全部源码)

前言 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;正在学习C/C、Java、Python等。 &#x1f4d7;本文收录于C语言进阶系列&#xff0c;本专栏主要内容为数据的存储、指针的进阶、字符串和内存函数的介绍、自定义类型结构、动态内存管理、文件操作等&#xff0…...

【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-响应协议…...

面试官:准备了一些springboot相关的面试题,快来看看吧

文章目录摘要Spring Boot 中的注解 RestController 和 Controller 有什么区别&#xff1f;Spring Boot 中如何处理异常&#xff1f;使用 ExceptionHandler 注解处理特定类型的异常&#xff1a;使用 ExceptionHandler 注解可以将特定类型的异常映射到一个处理方法上&#xff0c;…...

原子的波尔模型、能量量子化、光电效应、光谱实验、量子态、角动量

一. 卢瑟福模型 1908年&#xff0c;卢瑟福用α粒子继续轰击金箔&#xff0c;发现有极少数粒子&#xff0c;发生了非常大的偏移。而这对于当时主流的葡萄干面包模型理论分析是相悖的。 原子可看成由带正电的原子核和围绕核运动的一些电子组成&#xff0c;原子中心的原子核带正…...

【如何使用Arduino控制WS2812B可单独寻址的LED】

【如何使用Arduino控制WS2812B可单独寻址的LED】 1. 概述2. WS2812B 发光二极管的工作原理3. Arduino 和 WS2812B LED 示例3.1 例 13.2 例 24. 使用 WS2812B LED 的交互式 LED 咖啡桌4.1 原理图4.2 源代码在本教程中,我们将学习如何使用 Arduino 控制可单独寻址的 RGB LED 或 …...

计算机基本知识扫盲(持续更)

计算机基本知识扫盲Q&#xff1a;硬盘和磁盘有什么区别&#xff1f;A&#xff1a;硬盘和磁盘都是存储数据的设备。磁盘指的是存储数据的圆形或者是方形的光盘&#xff0c;但是硬盘则是指机械式硬盘和固态硬盘。磁盘一般用于存储少量数据&#xff0c;例如软件安装文件、音乐和电…...

学习大数据需要什么语言基础

Python易学&#xff0c;人人都可以掌握&#xff0c;如果零基础入门数据开发行业的小伙伴&#xff0c;可以从Python语言入手。 Python语言简单易懂&#xff0c;适合零基础入门&#xff0c;在编程语言排名上升最快&#xff0c;能完成数据挖掘、机器学习、实时计算在内的各种大数…...

ElasticSearch——详细看看ES集群的启动流程

参考&#xff1a;一起看看ES集群的启动流程 本文主要从流程上介绍整个集群是如何启动的&#xff0c;集群状态如何从Red变成Green&#xff0c;然后分析其他模块的流程。 这里的集群启动过程指集群完全重启时的启动过程&#xff0c;期间要经历选举主节点、主分片、数据恢复等重…...

【教学类-30-01】5以内加法题不重复(一页两份)(包含1以内、2以内、3以内、4以内、5以内加法,抽取最大不重复数量)

作品样式&#xff1a; 背景需求&#xff1a; 虽然学前阶段就对幼儿训练加减法列式题遭到诟病&#xff0c;但是从不少幼儿&#xff08;特别是二胎&#xff09;在家中已经开始适应加减法题型了。 结合中班年龄特点&#xff0c;我从5以内的不重复加法题开始实验&#xff08;雪花…...

写博客8年与人生第一个502万

题记&#xff1a;我们并非生来强大&#xff0c;但依然可以不负青春。 原本想好好写一下如何制定一个目标并通过一点一滴的努力去实现&#xff0c;这三年反思发现其实写自己的经历并不重要。 很多人都听过一句话&#xff1a;榜样的力量是无穷的。 更现实和实际的情况是&#x…...

【华为OD机试真题】日志采集系统(javapython)

日志采集系统 时间限制:1s空间限制:256MB限定语言:不限 题目描述: 日志采集是运维系统的的核心组件。日志是按行生成,每行记做一条,由采集系统分 批上报。 如果上报太频繁,会对服务端造成压力;如果上报太晚,会降低用户的体验;如果一 次上报的条数太多,会导致超时…...