• java编程基础总结——23.Set接口及其实现子类


    一、Set接口

    学习 Collection 接口时, Collection 中可以存放重复元素,也可以不存放重复元素,List中是可以存放重复元素的。那么不重复元素给哪里存放呢?那就是 Collection 接口中的 Set 集合中的元素就是不重复的。
    Set: 不包含重复元素的集合,不保证顺序,(具体是否有序要看子类实现,有的是基于二叉树实现的就是有序的) 而且方法和 Collection 一致。 Set 集合取出元素的方式只有 一种:迭代器。
    Set 集合有多个子类,这里我们介绍其中的 HashSet(哈希表) TreeSet(基于二叉树实现的,有序的) LinkedHashSet(链表结构的) 这三个集合。
    Set 方法完全来自 Collection 接口。

      对应数据结构中的哈希表:无序、不重复的非线性结构 

    set原码:

    不能包含重复元素的的集合,通常情况,set包含单独的值(map是键值对)

    二、.Set接口实现子类

    1. HashSet

    此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺
    序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。 是一个存放链表的数组

    1). 常见方法:

     add()、contains()

    1. @Test
    2. void testSet01() {
    3. // HashSet 是java中的一个标准的哈希表
    4. Collection nums = new HashSet<>();
    5. nums.add(123);
    6. nums.add(456);
    7. nums.add(789);
    8. nums.add(1);
    9. nums.add(13);
    10. nums.add(258);
    11. nums.add(10);
    12. System.out.println(nums);
    13. }

     和自己添加的值顺序不同,无序

    无序不是随机,会用特定的hash算法算值,而不是随机

    1. @Test
    2. void testSet01() {
    3. // HashSet 是java中的一个标准的哈希表
    4. Collection nums = new HashSet<>();
    5. nums.add(123);
    6. nums.add(456);
    7. nums.add(789);
    8. nums.add(1);
    9. nums.add(13);
    10. nums.add(258);
    11. nums.add(10);
    12. // add方法会返回一个boolean,表示是否添加成功
    13. System.out.println(nums.add(31));
    14. // 添加失败,返回false,表示之前已经存在了这个值
    15. System.out.println(nums.add(31));
    16. //是否包含某个元素
    17. System.out.println(nums.contains(1));
    18. System.out.println(nums.contains(11));
    19. System.out.println(nums);
    20. }

     2). 哈希表遍历

    注意:哈希表是无序的(没有下标),因此无法使用常规的循环,通过下标访问

    (1)迭代器访问

    1. @Test
    2. void testSet02() {
    3. // HashSet 是java中的一个标准的哈希表
    4. Collection nums = new HashSet<>();
    5. nums.add(123);
    6. nums.add(456);
    7. nums.add(789);
    8. nums.add(1);
    9. nums.add(13);
    10. nums.add(258);
    11. nums.add(10);
    12. //迭代器访问
    13. Iterator it = nums.iterator();
    14. while (it.hasNext()) {
    15. System.out.println(it.next());
    16. }
    17. }

    (2)for循环加强进行遍历

    for (Integer i : nums) {
            System.out.println(i);

    (3)forEach进行遍历

    nums.forEach((i) ->System.out.println(i));

    2. TreeSet:

        这个set是使用二叉树(红黑树)实现的一个集合,因此该集合是有序的

    1). 排序规律

    (1). 字符串按accll码值排序

    1. @Test
    2. void testSet03() {
    3. Set ss = new TreeSet<>();
    4. // 有序的集合
    5. ss.add("apply");
    6. ss.add("huawei");
    7. ss.add("mi");
    8. ss.add("mm");
    9. ss.add("vivo");
    10. ss.add("OPPO");
    11. System.out.println(ss);
    12. }

     

    (2). 数字按大小排序

    1. @Test
    2. void testSet04() {
    3. Set ss = new TreeSet<>();
    4. // 有序的集合
    5. ss.add(1);
    6. ss.add(2);
    7. ss.add(33);
    8. ss.add(333);
    9. ss.add(12);
    10. ss.add(102);
    11. ss.add(50);
    12. System.out.println(ss);
    13. }

    (3).对象

    先定义一个Person类

    1. package com.openlab.day20.entity;
    2. public class Person {
    3. private int id;
    4. private String name;
    5. private String nickname;
    6. private String gender;
    7. private int age;
    8. public int getId() {
    9. return id;
    10. }
    11. public void setId(int id) {
    12. this.id = id;
    13. }
    14. public String getName() {
    15. return name;
    16. }
    17. public void setName(String name) {
    18. this.name = name;
    19. }
    20. public String getNickname() {
    21. return nickname;
    22. }
    23. public void setNickname(String nickname) {
    24. this.nickname = nickname;
    25. }
    26. public String getGender() {
    27. return gender;
    28. }
    29. public void setGender(String gender) {
    30. this.gender = gender;
    31. }
    32. public int getAge() {
    33. return age;
    34. }
    35. public void setAge(int age) {
    36. this.age = age;
    37. }
    38. public Person() {
    39. }
    40. public Person(int id, String name, String nickname, String gender, int age) {
    41. super();
    42. this.id = id;
    43. this.name = name;
    44. this.nickname = nickname;
    45. this.gender = gender;
    46. this.age = age;
    47. }
    48. @Override
    49. public String toString() {
    50. return "Person [id=" + id + ", name=" + name + ", nickname=" + nickname + ", gender=" + gender + ", age=" + age
    51. + "]";
    52. }
    53. }
    1. @Test
    2. void testSet06() {
    3. Set ss = new TreeSet<>();
    4. ss.add(new Person(1, "cc", "曹孟德", "男", 32));
    5. ss.add(new Person(2, "lb", "刘玄德", "男", 28));
    6. ss.add(new Person(3, "sq", "孙百万", "男", 18));
    7. ss.add(new Person(4, "zf", "张翼德", "男", 24));
    8. ss.add(new Person(5, "gy", "关云长", "男", 26));
    9. ss.add(new Person(6, "hhd", "夏侯惇", "男", 43));
    10. ss.add(new Person(7, "lb", "吕奉先", "男", 23));
    11. ss.add(new Person(8, "dc", "貂蝉", "男", 16));
    12. System.out.println(ss);
    13. }

     

     

    jvm不知道Person类应该怎样排序

    String和Integer在定义的时候已经指定了排序规则,而我们自己写的Person没有制定规则,是让jvm自动去完成,但是jvm也不知道

    注意:在java中,如果对象需要比较,则必须让该类实现Comparable接口

    String和Integer(包装类)都实现了此接口

     

     所以Person要想进行比较也需要实现Comparable接口

    要求传递一个跟原对象进行比较

     Comparable接口有个泛型,要求传递过来一个东西跟原对象进行比较,我们传递Person,比较比较同一个对象,不是同一个对象比较没有意义

    重写方法:

    该方法返回一个int的值

    若返回一个 >0 的数,按照正序排序

    若返回一个 <0 的数,按照降序排序

    若返回一个 =0 的数,不变

    @Override

    public int compareTo(Person o) {
            return 0;

    }

    1. package com.openlab.day20.entity;
    2. public class Person implements Comparable {
    3. private int id;
    4. private String name;
    5. private String nickname;
    6. private String gender;
    7. private int age;
    8. public int getId() {
    9. return id;
    10. }
    11. public void setId(int id) {
    12. this.id = id;
    13. }
    14. public String getName() {
    15. return name;
    16. }
    17. public void setName(String name) {
    18. this.name = name;
    19. }
    20. public String getNickname() {
    21. return nickname;
    22. }
    23. public void setNickname(String nickname) {
    24. this.nickname = nickname;
    25. }
    26. public String getGender() {
    27. return gender;
    28. }
    29. public void setGender(String gender) {
    30. this.gender = gender;
    31. }
    32. public int getAge() {
    33. return age;
    34. }
    35. public void setAge(int age) {
    36. this.age = age;
    37. }
    38. public Person() {
    39. }
    40. public Person(int id, String name, String nickname, String gender, int age) {
    41. super();
    42. this.id = id;
    43. this.name = name;
    44. this.nickname = nickname;
    45. this.gender = gender;
    46. this.age = age;
    47. }
    48. @Override
    49. public String toString() {
    50. return "Person [id=" + id + ", name=" + name + ", nickname=" + nickname + ", gender=" + gender + ", age=" + age
    51. + "]";
    52. }
    53. @Override
    54. public int compareTo(Person o) {
    55. // 指定需要排序的规则!!!
    56. // 指定规则:id的升序排列
    57. // return this.getId() - o.getId();
    58. // 指定规则:age的降序排列
    59. return o.getAge() - this.getAge();
    60. }
    61. }

     return this.getId() - o.getId();

    比较当前对象和下一个对象的id,如果大于零,相当于return 1,

    代码相当于

    int temp = this.getId() - o.getId();

    if(temp > 0){

            return 1;

    }else{

            return -1;

    }

     

    2). 去重

    且TreeSet是有序的

    HashSet就不是了

    1. @Test
    2. void testSet05() {
    3. // 生成一个大小固定的list
    4. List list = Arrays.asList(1,3,34,5,5,6,7,88,8,8,88,99);
    5. Set ss = new TreeSet<>();
    6. Set s = new HashSet<>();
    7. ss.addAll(list);
    8. System.out.println(ss);
    9. s.addAll(list);
    10. System.out.println(s);
    11. }

     

     Arrays.asList() 将不定长的数据以ArrayList的形式返回,返回的是一个固定大小的ArrayList(传了几个数据就是几个,不能再改变)

    三、LinkedHashSet

    具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。此实现与 HashSet 的不同之外在
    于,后者维护着一个运行于所有条目的双重链接列表。
    此类提供所有可选的 Set 操作,并且 允许 null 元素。
    HashSet 一样,它可以为基本操作( add contains remove )提供稳定的性能,假
    定哈希函数将元素正确地分布到存储段中。由于增加了维护链接列表的开支,其性能很可能会比
    HashSet 稍逊一筹,不过,这一点例外: LinkedHashSet 迭代所需时间与 set 大小 成正比,而
    与容量无关。 HashSet 迭代很可能支出较大,因为它所需迭代时间与其 容量 成正比。
    此实现不是同步的。
  • 相关阅读:
    Android Automotive (一) 介绍
    Arduino是如何实现打开串口时,程序复位的?
    Linux cd 命令使用介绍
    Vue插槽slot
    P2895 [USACO08FEB]Meteor Shower S
    Spring中各个jar包的作用
    ElasticSearch复合查寻
    移动APP开发框架盘点2:Web移动前端框架大全
    4G LTE教程
    学历提升中的我,入职产品经理之路
  • 原文地址:https://blog.csdn.net/m0_58679504/article/details/126217047