进阶JAVA篇-深入了解 Set 系列集合

news2024/11/19 1:29:01

目录

        1.0 Set 类的说明

        1.1 Set 类的特点

        1.2 Set 类的常用API

        2.0 HashSet 集合的说明

        2.1 从 HashSet 集合的底层原理来解释是如何实现该特性

        2.2 HashSet 集合的优缺点

        2.3 深入理解 HashSet 集合去重的机制

        2.4 如何快速编写已经重写好的 hashCode 和 equals 方法

        3.0 TreeSet 集合的说明


        1.0 Set 类的说明

        Set 是 Java 中的一个集合类,它实现了 Set 接口Set 是一个不允许包含重复元素的集合,它是通过哈希表实现的,不保证元素的顺序

        1.1 Set 类的特点

  1. 不允许包含重复元素:Set 类中的元素是唯一的,如果试图向 Set 中添加重复元素,则添加操作将被忽略。
  2. 无序性:Set 类中的元素没有固定的顺序,元素的顺序可能发生变化。
  3. 不可变性:Set 类中的元素是不可变的,即不能修改 Set 中的元素。如果需要修改元素,需要先将元素从 Set 中删除,然后再添加修改后的元素。
  4. 元素的唯一性:Set 类中的元素是通过 hashCode() equals() 方法来判断是否相等的。如果两个元素的 hashCode 值相等,并且 equals 方法返回 true,则认为这两个元素相等。

          1.2 Set 类的常用API

以代码的形式来介绍:

import java.util.HashSet;
import java.util.Set;

public class Text_Set {
    public static void main(String[] args) {

        //由于 Set 类是子接口,故不能直接创建该类的对象,
        //所以用 Set 类的实现类 HashSet 类来实现该接口的方法
        Set<String> set = new HashSet<>();
        //1. add(element):向set中添加一个元素。
        set.add("张三");
        set.add("李四");
        set.add("王五");
        set.add("张麻子");
        System.out.println(set);
        //输出结果为:[李四, 张三, 王五, 张麻子]

        //2. remove(element):从set中删除一个元素。
        set.remove("张麻子");
        System.out.println(set);
        //输出的结果为:[李四, 张三, 王五]

        //3. contains(element):判断set中是否包含指定的元素。
        boolean b = set.contains("张麻子");
        System.out.println(b);
        //输出的结果为:false

        //4. size():获取set的大小,即set中元素的个数。
        int i = set.size();
        System.out.println(i);
        //输出的结果为: 3

        //5. isEmpty():判断set是否为空,即set中是否没有元素。
        boolean a = set.isEmpty();
        System.out.println(a);
        //输出结果为:false

        //6. clear():清空Set,即删除Set中的所有元素。
        set.clear();
        System.out.println(set);
        //输出的结果为:[]
    }
}

运行结果如下:

        其实这些方法都是 Set 子接口继承了 Collection 父接口的方法,有关 Collection 接口的常用 API 介绍在以下链接:

进阶JAVA篇- Collection 类的常用的API与 Collection 集合的遍历方式-CSDN博客

        

        2.0 HashSet 集合的说明

        HashSet 是 Java 中的一个集合类,它实现了 Set 接口HashSet 基于哈希表实现,不保证元素的顺序,且不允许包含重复元素。简单来说,继承了 Set 的特性:无序、不可重复、无索引

        2.1 从 HashSet 集合的底层原理来解释是如何实现该特性

        HashSet 集合是基于哈希表来实现的,又可以简单的认为是基于数组、链表、红黑树来实现的。

        补充哈希值的知识点:就是 int 类型的数值,Java 中的每一对象都有一个哈希值,都可以通过调用 Object 类提供的 hashCode() 方法,返回该对象自己的哈希值。

        要注意的是:一个相同的对象多次调用 hashCode() 方法返回的哈希值是相同的。对于不同对象调用 hashCode() 方法返回大多数的哈希值是不一致的,但是也有可能会相同(哈希碰撞)。

JDK8之前 HashSet 集合的底层原理:

Set<String> set = new HashSet<>();

        首先,在执行以上代码的时候,底层会创建一个默认为16的数组,默认加载因子为0.75,数组名为table .

        

set.add("张三");

        然后,在执行到以上代码的时候,使用该字符串对象的哈希值对长度求余计算出相应存入的位置。比如这个对象的哈希值为 3%16 == 3,应该会放到数组下标为3的数组内存中,因此在这里我们就可以解释了 HashSet() 类的无序性,并不是按添加元素的前后顺序而放到数组内存中的。

        在此之前并不着急存入,先要判断当前的位置是否为 null ,如果是 null 直接回存入,如果不是 null,表示有元素,则回调用 equals 方法来比较相等,则不存;不相等,则存入到数组中。因此在这里我们就可以解释了 HashSet() 类的不可重复性。

        如果数组快占满的时候,链表会过长,导致查询性能下降,这时候就会扩容,如果元素增加超过当前数组长度  * 默认加载因子,即 16 * 0.75 == 12 ,超过12是,就会自动扩容。

        从JDK8开始,如果链表长度超过8,且数组长度 >= 64时,会自动将链表转变为红黑树。

        2.2 HashSet 集合的优缺点

        HashSet 集合基于这种哈希表的数据结构,查询、增加、删除、修改元素速度都很快,性能很高。

        2.3 深入理解 HashSet 集合去重的机制

        由于 HashSet 集合默认不能对内容相同的不同对象去重。

代码如下:

import java.util.HashSet;
import java.util.Set;

public class Text_Set {

    public static void main(String[] args) {
        Student s1 = new Student("张三",19);
        Student s2 = new Student("张三",19);

        Set<Student> studentSet = new HashSet<>();
        studentSet.add(s1);
        studentSet.add(s2);
        System.out.println(studentSet);
    }
}

运行结果如下:

        内容相同的两个不同对象。

       HashSet 中的元素是通过 hashCodeequals 方法来判断是否相等的。如果两个元素的hashCode 值相等,并且 equals 方法返回 true,则认为这两个元素相等。

        具体的解决办法就是将两个内容相同的不同对象改为相同的哈希值。需要重写两个方法,hashCodeequals 方法 。

完整代码如下:

Student 类:

import java.util.Objects;

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
import java.util.HashSet;
import java.util.Set;

public class Text_Set {

    public static void main(String[] args) {
        Student s1 = new Student("张三",19);
        Student s2 = new Student("张三",19);

        Set<Student> studentSet = new HashSet<>();
        studentSet.add(s1);
        studentSet.add(s2);
        System.out.println(studentSet);
    }
}

运行结果如下:

        2.4 如何快速编写已经重写好的 hashCode 和 equals 方法

        在 IDEA 中已经帮我们写好了这些方法。在该类中点击右键,选择点击”生成“,最后选择重写这两个方法即可。

        3.0 TreeSet 集合的说明

        TreeSet 是 Java 中的一个集合类,它实现了 Set 接口,是一个有序的集合。TreeSet 底层是通过红黑树来实现的,可以保证元素的有序性。其特性是有序(升序)、不可重复、无索引。

        对于自定的类型如 Student 类型,TreeSet 默认是不能排序的。

  1. Comparable接口: Comparable 接口是 Java 提供的一个用于比较对象的接口,它定义了一个 compareTo 方法,用于比较当前对象和另一个对象的大小关系。如果一个类实现了Comparable 接口,就表示该类的对象是可比较的,可以用于排序。
  2. Comparator 接口: Comparator 接口是 Java 提供的一个用于比较对象的接口,它定义了一个 compare 方法,用于比较两个对象的大小关系。与 Comparable 接口不同的是,Comparator 接口可以在排序时动态地指定比较规则,而不需要修改被比较的类。

具体解决代码如下:

方法一:

Student 类

public class Student implements Comparable<Student>{
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Student o) {
        return this.age - o.age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
import java.util.Set;
import java.util.TreeSet;

public class Text_TreeSet {
    public static void main(String[] args) {
        Student s1 = new Student("张三",19);
        Student s2 = new Student("李四",33);
        Student s3 = new Student("王五",21);

        Set<Student> studentSet = new TreeSet<>();
        studentSet.add(s1);
        studentSet.add(s2);
        studentSet.add(s3);
        System.out.println(studentSet);

    }
}

运行结果如下:

 方法二:(为了区分前面的方法,按降序的方法来排序)

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

public class Text_TreeSet {
    public static void main(String[] args) {
        Student s1 = new Student("张三",19);
        Student s2 = new Student("李四",33);
        Student s3 = new Student("王五",21);

        Set<Student> studentSet = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o2.getAge()-o1.getAge();
            }
        });
        studentSet.add(s1);
        studentSet.add(s2);
        studentSet.add(s3);
        System.out.println(studentSet);

    }
}



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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

空中计算(Over-the-Air Computation)学习笔记

文章目录 写在前面 写在前面 本文是论文A Survey on Over-the-Air Computation的阅读笔记&#xff1a; 通信和计算通常被视为独立的任务。 从工程的角度来看&#xff0c;这种方法是非常有效的&#xff0c;因为可以执行孤立的优化。 然而&#xff0c;对于许多面向计算的应用程序…

【Arduino TFT】基于 ESP32S3 S7789 240x240 TFT实现的SD2 天气时钟

忘记过去&#xff0c;超越自己 ❤️ 博客主页 单片机菜鸟哥&#xff0c;一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2023-10-21 ❤️❤️ 本篇更新记录 2023-10-21 ❤️&#x1f389; 欢迎关注 &#x1f50e;点赞 &#x1f44d;收藏 ⭐️留言&#x1f4dd;&#x1f64…

口袋参谋:如何找蓝海词?带动店铺搜索流量!

​为什么店铺没流量&#xff1f;很多新手商家在优化标题的时候从来不找词&#xff0c;凭着自己的想象做标题&#xff0c;这种情况很难获得流量。 要想获得更多的流量&#xff0c;符合产品属性的蓝海词是我们当属首选&#xff0c;不用和红海词去竞争&#xff0c;更不用和比较有…

java springboot+VUE OA企业办公自动化系统前后端分离开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot VUE OA企业办公自动化系统是一套完善的完整信息管理类型系统&#xff0c;结合springboot框架和VUE完成本系统 后端采用mybatis进行数据库交互&#xff0c;对理解JSP java编程开发语言有帮 助系统采用springboot框架&#xff08;MVC模式开发&#xff…

Pandas数据处理分析系列4-数据如何清洗

Pandas-数据清洗 ①缺失值处理 使用fillna()函数将缺失值替换为指定的值或使用插值方法填充缺失值 示例:df.fillna(0) #将缺失值替换为0 import pandas as pddf1=pd.read_excel("销售表.xlsx") # 检查每列是否缺失 print(df1.isna) 效果如下: import pandas as …

std::string_view概念原理及应用

概念 使用const string&作为参数是先使用字符串字面量编译器会创建一个临时字符串对象然后创建std::string。 或者一个函数提供char*和const string&参数的两个版本函数&#xff0c;不是优雅的解决方案。 于是需要一个只使用内存不维护内存的类。 原理 在visual s…

数据结构——三路划分(快排优化)

刷Leetcode时遇到的问题&#xff0c;用普通的快排去跑&#xff0c;发现有问题。 普通的Hoare或者其他的快排好像都没有直接解决掉这个问题&#xff0c;当一个数重复出现的时候&#xff0c;用普通的快排效率其实并没有那么高。所以&#xff0c;这也是普通快排的缺点之一。 所以&…

STM32F4X之GPIO

一、GPIO概述 主控芯片信息如下&#xff1a; 主频&#xff1a;168MHZ内核&#xff1a;ARM-M4FLASH:1MSRAM:192KB引脚&#xff1a;100GPIO:82电压&#xff1a;1.8~3.6V 1.1GPIO概念及其作用 GPIO概念&#xff1a;通用输入输出(General Purpose Input Output)&#xff0c;主要作用…

解决报错【error: Microsoft Visual C++ 14.0 or greater is required】

当我们在环境中pip install某些python的依赖包时,直接pip install有时可能出现如下报错: error: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/,这说…

Linux搭建Redis环境

1. 基础环境 名称说明CentOS 7.6Linux操作系统版本redis-5.0.0.tar.gzRedis二进制安装包 2. 服务安装 服务端路径&#xff1a;usr/loacl/redis/redis-server客户端路径&#xff1a;usr/loacl/redis/redis-cli # 解压二进制包 [rootzhouwei resource]# tar -zxvf redis-5.0.…

IntelliJ IDEA 2023版本 Debug 时没有Force Step Into 按钮解决方法

IntelliJ IDEA 2023版本 Debug 时没有Force Step Into 按钮解决方法 force step into作用是能够去查看原码&#xff0c; 新版本idea默认移除了这个按钮&#x1f622; 那么让我们来把它找出来叭✋ 但是我们可以通过设置&#xff0c;使用step into就可以进入系统方法。 1.单击…

【TensorFlow1.X】系列学习笔记【入门二】

【TensorFlow1.X】系列学习笔记【入门二】 大量经典论文的算法均采用 TF 1.x 实现, 为了阅读方便, 同时加深对实现细节的理解, 需要 TF 1.x 的知识 文章目录 【TensorFlow1.X】系列学习笔记【入门二】前言神经网络的参数神经网络的搭建前向传播反向传播 总结 前言 学习了张量、…

react dispatch不生效的坑

一、前言 最近写react antd项目&#xff0c;在A页面中使用了dispatch方法&#xff0c;然后B页面中嵌套A页面&#xff0c;没有问题&#xff1b; 但是在C页面中嵌套A页面的时候&#xff0c;就发现dispatch方法没有执行&#xff0c;也不报错&#xff0c;就很奇怪&#xff1b; 还…

论坛介绍|COSCon'23 开源硬件(H)

众多开源爱好者翘首期盼的开源盛会&#xff1a;第八届中国开源年会&#xff08;COSCon23&#xff09;将于 10月28-29日在四川成都市高新区菁蓉汇举办。本次大会的主题是&#xff1a;“开源&#xff1a;川流不息、山海相映”&#xff01;各位新老朋友们&#xff0c;欢迎到成都&a…

navicate16在M1芯片运行问题

问题描述&#xff1a;本人M1芯片的mac&#xff0c;最近升级macOS14系统后&#xff0c;navicate15就总是闪退&#xff0c;如图 于是就安装了16的版本&#xff0c;但是16的版本不支持m1芯片电脑&#xff0c;如下图所示 于是就有了下面的操作&#xff0c;虽然能够使用了&#xff0…

【论文解读】The Power of Scale for Parameter-Efficient Prompt Tuning

一.介绍 1.1 promote tuning 和 prefix tuning 的关系 “前缀调优”的简化版 1.2 大致实现 冻结了整个预训练模型&#xff0c;并且只允许每个下游任务附加k个可调令牌到输入文本。这种“软提示”是端到端训练的&#xff0c;可以压缩来自完整标记数据集的信号&#xff0c;使…

数据图册页面(左边一列图片缩略图,右边展示图片大图)

最近要写这么一个页面&#xff0c;左侧一列图片缩略图&#xff0c;点击左侧缩略图后有选中效果&#xff0c;然后右侧展示图片原图&#xff0c;还能够左右翻页查看。 最后写了一个demo出来&#xff0c;demo还不是很完善&#xff0c;需要自己修改&#xff0c;后面我也给出了修改建…

发挥服务器的无限潜能:创意项目、在线社区和更多

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 ✨特色专栏&#xff1a…

ICMPv6与NDP

1. ICMPv6简介 ICMP概述 Internet控制消息协议ICMP (Internet Control Message Protocol)是IP协议的辅助协议。 ICMP协议用来在网络设备间传递各种差错和控制信息&#xff0c;对于收集各种网络信息、诊断和排除各种网络故障等方面起着至关重要的作用。 ICMP差错检查 ICMP …

Mingw快捷安装教程 并完美解决出现的下载错误:The file has been downloaded incorrectly

安装c语言编译器的时候&#xff0c;老是出现The file has been downloaded incorrectly&#xff0c;真的让人 直接去官网拿压缩包&#xff1a;https://sourceforge.net/projects/mingw-w64/files/ &#xff08;往下拉找到那个x86_64-win32-seh的链接&#xff0c;点击后会自动…