Java Set集合

news2024/9/24 17:09:08

7 Set集合

7.1 Set集合的概述和特点

  • Set集合的特点
    • 不包含重复元素的集合
    • 没有带索引的方法,所以不能使用普通for循环
  • Set集合是接口通过实现类实例化(多态的形式)
    • HashSet:添加的元素是无序,不重复,无索引的
    • LinkedHashSet: 添加的元素是有序,不重复,无索引的
    • TreeSet: 不重复,无索引,按照大小默认升序排列
package ceshi;

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

public class SetDemo {
    public static void main(String[] args) {
        //创建Set集合对象
        Set<String> set = new HashSet<>();

        //添加元素
        set.add("java");
        set.add("python");
        set.add("scala");
        //不包含重复元素
        set.add("java");

        //两种遍历方式
        for(String s:set) {
            System.out.println(s);
            /*python
            java
            scala*/
        }
        System.out.println("--------");

        Iterator<String> it = set.iterator();
        while(it.hasNext()) {
            String s = it.next();
            System.out.println(s);
            /*python
            java
            scala*/
        }
    }
}

7.2 哈希值

  • 哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
  • Object类中有一个方法可以获取对象的哈希值
    public int hashCode():返回对象的哈希码值
  • 对象的哈希值特点
    • 同一个对象多次调用hashCode()方法返回的哈希值是相同的
    • 默认情况下,不同对象的哈希值是不同的。而重写hashCode0方法,可以实现让不同对象的哈希值相同
package ceshi;

public class HashDemo {
    public static void main(String[] args) {
        //创建学生对象
        Student s1 = new Student("y1",10);

        //同一个对象多次调用hashCode()方法哈希值相同
        System.out.println(s1.hashCode()); //460141958
        System.out.println(s1.hashCode()); //460141958
        System.out.println("---------");

        //默认情况下,不同对象哈希值不同;重写hashCode()方法就可以使哈希值相同
        Student s2 = new Student("y2",20);
        System.out.println(s2.hashCode()); //1163157884
        System.out.println("---------");

        System.out.println("java".hashCode()); //3254818
        System.out.println("python".hashCode()); //-973197092
        System.out.println("scala".hashCode()); //109250886
        System.out.println("---------");

        System.out.println("无".hashCode()); //26080
        System.out.println("敌".hashCode()); //25932
    }
}

7.3 数据结构之哈希表

  • JDK8之前,底层采用数组+链表实现,可以说是一个元索为链表的数组(哈希表 = 数组 + 链表 + (哈希算法))
  • JDK8以后,在长度比较长的时候,底层实现了优化(哈希表 = 数组 + 链表 + 红黑树 + (哈希算法))
  • 当链表长度超过 8 时,将链表转换为红黑树,这样大大减少了查找时间
    在这里插入图片描述

7.4 HashSet集合概述和特点

  • HashSet集合特点
    • 底层数据结构是哈希表
    • 对集合的迭代顺序不作任何保证 ,也就是说不保证存储和取出的元素顺序一致
    • 没有带索引的方法,所以不能使用普通for循环遍历
    • 由于是Set集合, 所以是不包含重复元素的集合
package ceshi;

import java.util.HashSet;

public class HashSetDemo {
    public static void main(String[] args) {
        HashSet<String> hs = new HashSet<>();

        hs.add("java");
        hs.add("python");
        hs.add("scala");

        hs.add("scala");

        for(String s:hs) {
            System.out.println(s);
            /*python
            java
            scala*/
        }

    }
}

7.5 HashSet集合保证元素唯一性源码分析(重点面试常考)

在这里插入图片描述

HashSet<String> hs = new HashSet<>();

        hs.add("java");
        hs.add("python");
        hs.add("scala");

        hs.add("scala");

        for(String s:hs) {
            System.out.println(s);
            /*python
            java
            scala*/
        }
-----------------------------------
public boolean add(E e) {
   return map.put(e, PRESENT)==null;
}

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true); //上个方法的返回的值是hash(key)的值
}
//hash值和元素的hashCode()方法
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
              boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    //如果哈希表未初始化就对其初始化
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    //根据对象的哈希值计算对象的存储位置,
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null); //如果该位置没有元素,就存储新元素
    //有元素就走else
    else {
        Node<K,V> e; K k;
        //存入的元素和以前的元素比哈希值
        if (p.hash == hash && 
        	//二、如果哈希值相同,调用对象的equals()比较内容是否相同
        	//1、如果内容不同equals()返回false,就走一把元素添加到集合
        	//2、如果内容相同返回true,说明元素重复,走e = p;不存储
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        //一、如果哈希值不同,就走else存储元素到集合
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null); //新元素添加到集合
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}
  • HashSet集合存储元素:要保证元素唯一性需要重写hashCode()equals()方法

  • 案例
    在这里插入图片描述

  • Student类

package ceshi;

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

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = 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;
    }

    //重写快捷键:Fn+Alt+insert,选择equals() and hashCode()
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
}
  • 测试类
package ceshi;

import java.util.HashSet;

public class HashSetDemo {
    public static void main(String[] args) {
        HashSet<Student> hs = new HashSet<>();

        Student s1 = new Student("y1",10);
        Student s2 = new Student("y2",20);
        Student s3 = new Student("y3",30);
        Student s4 = new Student("y3",30);

        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);

        for(Student s: hs) {
            System.out.println(s.getName()+","+s.getAge());
            /*y3,30
            y2,20
            y1,10
            y3,30;s4内容和s3重复并存入了,需要重写hashCode()和equals()
            */

            //重写后
            /*
            y1,10
            y3,30
            y2,20*/
        }
    }
}

7.6 LinkedHashSet集合概述和特点

  • LinkedHashSet集合特点
    • 哈希表和链表实现的Set接口, 具有可预测的迭代次序
    • 由链表保证元素有序, 也就是说元索的存储和取出顺序是一致的
    • 由哈希表保证元索唯一, 也就是说没有重复的元素
package ceshi;

import java.util.LinkedHashSet;

public class LinkedHashSetDemo {
    public static void main(String[] args) {
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();

        linkedHashSet.add("java");
        linkedHashSet.add("python");
        linkedHashSet.add("scala");
        linkedHashSet.add("scala");

        for(String s:linkedHashSet) {
            System.out.println(s);
            /*java
            python
            scala*/
        }
    }
}

7.7 TreeSet集合概述和特点

  • TreeSet集合特点

    • 元素有序, 这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
      TreeSet():根据其元素的自然排序进行排序
      TreeSet(Comparator comparator):根据指定的比较器进行排序
    • 没有带索引的方法,所以不能使用普通for循环遍历
    • 由于是Set集合,所以不包含重复元素的集合
package ceshi;

import java.util.TreeSet;

public class TreeSetDemo {
    public static void main(String[] args) {
        TreeSet<Integer> ts = new TreeSet<>();

        //jdk5以后添加元素自动装箱int》integer
        ts.add(10);
        ts.add(40);
        ts.add(30);
        ts.add(50);
        ts.add(20);

        ts.add(30);

        for(Integer i:ts) {
            System.out.println(i);
            /*
            10
            20
            30
            40
            50*/
        }

    }
}

7.8 自然排序Comarable的使用

  • 存储学生对象并遍历,创建TreeSet集合使用无参构造方法

  • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

  • 结论:

    • 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
    • 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
    • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
  • Student类

package ceshi;

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;
    }

    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 int compareTo(Student s) {
//        return 0; //返回0说明元素是重复的,只能存一个元素
//        return 1; //整数是升序排序
//        return -1; //负数是倒叙排序
        //按照年龄排序
        int num = this.age-s.age; //this是s2,s是s1
        //年龄相同时,按照名字字母排序
        int num2 = num==0 ? this.name.compareTo(s.name):num;
        return num2;
    }
}
  • 测试
package ceshi;

import java.util.TreeSet;

public class TreeSetDemo {
    public static void main(String[] args) {
        TreeSet<Student> ts = new TreeSet<>();

        Student s1 = new Student("y1",10);
        Student s2 = new Student("y3",30);
        Student s3 = new Student("y2",20);
        Student s4 = new Student("y4",40);

        Student s5 = new Student("a4",40); //判断按字母排序

        Student s6 = new Student("y4",40); //判断会存储重复值吗

        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);

        for(Student s:ts) {
            System.out.println(s.getName()+","+s.getAge());
            /*y1,10
            y2,20
            y3,30
            a4,40
            y4,40*/
        }
    }
}

7.9 比较器排序Comparator[kəmˈpɜrətər]的使用

  • 存储学生对象并遍历,创建TreeSet集合使用带参构造方法
  • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
  • 结论
    • 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元索进行排序的
    • 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(To1,T o2)方法
    • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
package ceshi;

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

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = 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;
    }

}
  • 测试
package ceshi;

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

public class TreeSetDemo {
    public static void main(String[] args) {
        TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num = s1.getAge() - s2.getAge();
                int num2 = num==0? s1.getName().compareTo(s2.getName()):num;
                return num2;
            }
        });

        Student s1 = new Student("y2",20);
        Student s2 = new Student("y1",10);
        Student s3 = new Student("y3",30);
        Student s4 = new Student("y4",40);

        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);

        for(Student s:ts) {
            System.out.println(s.getName()+","+s.getAge());
        }
    }
}

7.10 案例:不重复随机数

在这里插入图片描述

package ceshi;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;

public class SetDemo {
    public static void main(String[] args) {
//        Set<Integer> set = new HashSet<>();
        Set<Integer> set = new TreeSet<>();

        Random r = new Random();
        //判断集合是否《10
        while(set.size()<10) {
            int number = r.nextInt(20)+1;
            set.add(number); //把随机数添加到集合
        }

        for (Integer i:set) {
            System.out.print(i+" "); //1(哈希set集合):16 17 2 20 8 9 10 11 14 15
            //2(TreeSet集合):1 3 4 5 6 7 8 10 16 19 
        }
    }
}

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

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

相关文章

线程和QObjects

QObject的可重入性&#xff1a; QThread继承了QObject&#xff0c;它发出信号以指示线程开始或完成执行&#xff0c;并提供一些插槽。 QObjects可以在多个线程中使用发出调用其他线程中槽的信号&#xff0c;并将事件发布到在其他线程中“活动”的对象。这是可能的&#xff0…

redis可视工具AnotherRedisDesktopManager的使用

redis可视工具AnotherRedisDesktopManager的使用 简介 Another Redis DeskTop Manager 是一个开源项目&#xff0c;提供了以可视化的方式管理 Redis 的功能&#xff0c;可供免费下载安装&#xff0c;也可以在此基础上进行二次开发&#xff0c;主要特点有&#xff1a; 支持 W…

Matlab中安装NURBS工具箱及使用

文章目录前言一、NURBS工具箱的安装1 打开matlab&#xff0c;点击附加功能2 输入nurbs3 下载后压缩包解压4 将解压后的文件夹放到matlab文件夹的toolbox文件夹里面5 选择“预设路径”上方的“预设”二、NURBS工具箱的使用2.1 NURBS 结构&#xff1a;2.2 对NURBS工具箱的初步理解…

关于表的操作 数据库(3)

目录 前期准备工作&#xff1a; 一、单表查询&#xff1a; 二、多表查询&#xff1a; 前期准备工作&#xff1a; 修改数据库的配置文件&#xff0c;&#xff0c;使其可以显示库名&#xff0c;其中//d代表当前使用的数据库名 注&#xff1a;vim /etc/my.cnf.d/mysql-server.c…

Session与Cookie的区别(四)

咖啡寄杯的烦恼 虽然店里生意还可以&#xff0c;但小明无时无刻不想着怎么样发大财赚大钱&#xff0c;让店里的生意变得更好。 他观察到最近好多便利商店开始卖起了咖啡&#xff0c;而且时不时就买一送一或是第二件半价&#xff0c;并且贴心地提供了寄杯的服务。 寄杯就是指说你…

《剑指offer》:数组部分

一、数组中重复的数字题目描述&#xff1a;在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的&#xff0c;但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如&#xff0c;如果输入长度为7的数组{2,3,1…

C语言fscanf和fprintf函数的用法详解

fscanf() 和 fprintf() 函数与前面使用的 scanf() 和 printf() 功能相似&#xff0c;都是格式化读写函数&#xff0c;两者的区别在于 fscanf() 和 fprintf() 的读写对象不是键盘和显示器&#xff0c;而是磁盘文件。这两个函数的原型为&#xff1a;int fscanf ( FILE *fp, char …

【力扣-LeetCode】1138. 字母板上的路径-C++题解

1138. 字母板上的路径难度中等98收藏分享切换为英文接收动态反馈我们从一块字母板上的位置 (0, 0) 出发&#xff0c;该坐标对应的字符为 board[0][0]。在本题里&#xff0c;字母板为board ["abcde", "fghij", "klmno", "pqrst", &quo…

点云转3D网格【Python】

推荐&#xff1a;使用 NSDT场景设计器 快速搭建 3D场景。 在本文中&#xff0c;我将介绍我的 3D 表面重建过程&#xff0c;以便使用 Python 从点云快速创建网格。 你将能够导出、可视化结果并将结果集成到您最喜欢的 3D 软件中&#xff0c;而无需任何编码经验。 此外&#xff0…

总投资超500亿,广州白云机场三期扩建工程的IT投资更吸引人

【科技明说 | 每日看点】2023年基建大工程计划出台&#xff0c;广州白云机场三期将落实百亿元投资引发业内关注。据悉&#xff0c;广州白云机场三期扩建工程投资达537.7亿元&#xff0c;计划于2025年建成投产。这是中国民航历史上规模最大的改扩建工程&#xff0c;其扩建工程今…

TC3xx FlexRay™ 协议控制器 (E-Ray)-01

1 FlexRay™ 协议控制器 (E-Ray) E-Ray IP 模块根据为汽车应用开发的 FlexRay™ 协议规范 v2.1 执行通信【performs communication according to the FlexRay™ 1) protocol specification v2.1】。使用最大指定时钟&#xff0c;比特率可以编程为高达 10 Mbit/s 的值。连接到物…

Fluent Python 笔记 第 5 章 一等函数

在 Python 中&#xff0c;函数是一等对象。编程语言理论家把“一等对象”定义为满足下述条件的程 序实体: 在运行时创建能赋值给变量或数据结构中的元素 • 能作为参数传给函数能作为函数的返回结果 5.1 把函数视作对象 会用 map。 5.2 高阶函数 接受函数为参数&#xff0…

基于JAVA的超级玛丽设计与实现

技术&#xff1a;Java等摘要&#xff1a;随着计算机技术及网络技术的不断发展&#xff0c;电子游戏越来越普及。经典游戏“超级玛丽”因其本身所具有的娱乐性与教育意义而被人们广泛接受&#xff0c;在广大的青少年玩家中享有极高的知名度。Java语言作为一种完全面向对象的程序…

【AI 交互式聊天】无需等待 Bing ChatGPT : 已经有一个基于搜索结果响应的 AI 交互式聊天网站了!Perplexity

Perplexity: https://www.perplexity.ai 同样的问题&#xff0c;我问ChatGPT&#xff0c;回答如下&#xff1a; 实现财富自由需要一系列的步骤和策略&#xff0c;以下是一些建议&#xff1a; 1. 设定目标&#xff1a;明确你的财务目标&#xff0c;并制定一个有目标的计划来实…

吾爱破解2023安卓中级题

先来看看APP界面 拖到jadx&#xff0c;see see java 源码 关键是要让代码跳转到这里&#xff0c;我这里主要是修改smali&#xff0c;然后重新签名打包&#xff0c;当然&#xff0c;你也可以用frida或者objection hook 传参 模仿下面的两行代码&#xff0c;在位置1插入 :cond_6…

循环队列来了解一下!!

笔者在之前的一篇文章&#xff0c;详细的介绍了&#xff1a;队列之单向链表与双向链表的模拟实现&#xff1a;https://blog.csdn.net/weixin_64308540/article/details/128742090?spm1001.2014.3001.5502 感兴趣的各位老铁&#xff0c;可以参考一下啦&#xff01;下面进入循环…

基于Java+SpringBoot+Vue前后端分离酒店管理系统设计与实现

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建、毕业项目实战、项目定制✌ 博主作品&#xff1a;《微服务实战》专栏是本人的实战经验总结&#xff0c;《S…

linux系统常用命令

目录 一、系统介绍 二、Linux常用命令 1、Linux命令格式 2、文件目录操作命令&#xff1a;ls 3、文件目录操作命令&#xff1a;cd 4、文件目录操作命令&#xff1a;cat 5、文件目录操作命令&#xff1a;more 6、文件目录操作命令&#xff1a;tail 7、创建文件命令&…

【三维点云】01-激光雷达原理与应用

文章目录内容概要1 激光雷达原理1.1 什么是激光雷达&#xff1f;1.2 激光雷达原理1.3 激光雷达分类三角法TOF法脉冲间隔测量法幅度调制的相位测量法相干法激光雷达用途2 激光雷达安装、标定与同步2.1 激光雷达安装方式考虑因素2.2 激光雷达点云用途2.3 数据融合多激光雷达数据融…

Rust学习入门--【7】Rust 数据类型

类型系统 对于任何一门语言都是重中之重&#xff0c;因为它体现了语言所支持的不同类型的值。 类型系统 也是 IT 初学者最难啃的三座大山之一&#xff0c;而类型系统之所以难以理解&#xff0c;主要是没有合适的现成的参考体系。 我们说类型系统 存在的目的&#xff0c;就是 …