Set集合

简介: Set接口也是Collection的子接口,Set接口没有提供额外的方法。Set集合支持的遍历方式也和Collection集合一样,使用foreach和Iterator遍历。

@toc

1、Set集合

  Set接口也是Collection的子接口,Set接口没有提供额外的方法。Set集合支持的遍历方式也和Collection集合一样,使用foreach和Iterator遍历。

  ==Set集合不允许包含相同的元素==,如果试图把两个相同的元素加入同一个Set集合,则添加操作失败,操作失败并不会报错,只是添加不成功而已。Set接口的常用实现类有:HashSetLinkedHashSetTreeSet

1.1 HashSet和LinkedHashSet

  HashSet是Set接口的典型实现类,大多数时候使用Set集合时都会使用这个实现类。

  HashSet和LinkedHashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。==HashSet和LinkedHashSet集合判断两个元素相等的标准是两个对象通过hashCode方法比较,并且两个对象的equals方法返回值也相等。==

  LinkedHashSet是HashSet的子类,它在HashSet的基础上,在结点中增加两个属性(before和after)以维护结点的前后添加顺序。LinkedHashSet插入性能略低于HashSet,但在迭代访问Set中的全部元素时有很好的性能。

  示例代码:

  HashSet添加元素的示例代码:

public class HashSetTest {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("张三");
        set.add("李四");
        set.add("王五");
        set.add("张三");//尝试添加重复元素

        System.out.println("元素个数:"+set.size());
        for (Object obj : set) {
            System.out.println(obj);
        }

    }
}

image-20221004160236033

  LinkedHashSet添加元素的示例代码:

public class LinkedHashSetTest {
    public static void main(String[] args) {
        LinkedHashSet<String> set = new LinkedHashSet<>();
        set.add("张三");
        set.add("李四");
        set.add("王五");
        set.add("张三");//尝试添加重复元素

        System.out.println("元素个数:"+set.size());
        for (Object obj : set) {
            System.out.println(obj);
        }

    }
}

image-20221004160520890

  从上面代码的结果中可以看出,HashSet不保证元素的添加顺序,但是LinkedHashSet可以保证元素的添加顺序。无论是HashSet还是LinkedHashSet都不允许添加重复元素

1.2 案例:员工信息管理

  案例需求:定义一个Employee类,该类包含name、birthday,要求name和恶birthday相等的为同一个员工,其中birthday为MyDate类,包含年、月、日三个属性。尝试重写Employee类的hashCode方法和equals方法。

  MyDate类代码:

import java.util.Objects;

public class MyDate {
    private int year;
    private int month;
    private int day;

    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    @Override
    public String toString() {
        return "MyDate{" +
                "year=" + year +
                ", month=" + month +
                ", day=" + day +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyDate myDate = (MyDate) o;
        return year == myDate.year &&
                month == myDate.month &&
                day == myDate.day;
    }

    @Override
    public int hashCode() {
        return Objects.hash(year, month, day);
    }
}

  Employee类示例代码:

import java.util.Objects;

public class Employee {
    private String name;//姓名
    private MyDate birthday;//生日

    public Employee(String name, MyDate birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    //重写equals方法-判断姓名和生日是否相等
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Objects.equals(name, employee.name) &&
                Objects.equals(birthday, employee.birthday);
    }

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

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}

  测试类示例代码:

import java.util.HashSet;

public class TestEmployee {
    public static void main(String[] args) {
        HashSet<Object> set = new HashSet<>();

        set.add(new Employee("张三",new MyDate(1990,1,1)));
        //重复元素无法添加,因为MyDate和Employee重写了hashCode和equals方法
        set.add(new Employee("张三",new MyDate(1990,1,1)));
        set.add(new Employee("李四",new MyDate(1992,2,2)));

        for (Object o : set) {
            System.out.println(o);
        }
    }
}

  代码运行结果:

image-20221004161058327

1.3 TreeSet

  SortedSet是Set接口的一个子接口,支持排序类Set集合,TreeSet是SortedSet接口的实现类,即TreeSet可以确保集合元素处于排序状态。

  对象的排序要么是对象本身支持自然排序,即实现java.lang.Compareable接口,要么在创建set集合对象时提供定值排序接口java.util.Comparator的实现类对象。

1.3.1 自然排序

  如果视图把一个对象添加到未指定定制比较器的TreeSet时,则该对象的类必须实现Comparable接口,实现compareTo(Object obj)方法。此时对于TreeSet集合而言,它判断两个对象是否相等的唯一标准是两个对象通过compareTo(Object obj)方法比较返回值为0.

  示例代码:

  元素为String类,String类实现了java.lang.Conparable自然排序接口的示例代码:

import java.util.TreeSet;

public class TreeSetTest1 {
    public static void main(String[] args) {
        TreeSet<Object> set = new TreeSet<>();

        //String它实现了java.lang.Comparable接口
        set.add("zhangsan");
        set.add("lisi");
        set.add("wangwu");
        set.add("zhangsan");

        System.out.println("元素个数:"+set.size());
        for (Object o : set) {
            System.out.println(o);
        }
    }
}

image-20221004162151940

  学生类实现了java.lang.Comparable自然排序接口的示例代码:

public class Student implements Comparable {
    private int id;
    private String name;

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public int compareTo(Object o) {
        Student other=(Student) o;
        return this.id-other.id;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

  测试类示例代码:

public class TreeSetTest2 {
    public static void main(String[] args) {
        TreeSet<Object> set = new TreeSet<>();

        //Student实现了java.lang.Comparable接口
        set.add(new Student(3,"张三"));
        set.add(new Student(1,"李四"));
        set.add(new Student(2,"王五"));
        set.add(new Student(3,"张三凤"));

        System.out.println("元素个数:"+set.size());
        for (Object o : set) {
            System.out.println(o);
        }
    }
}

image-20221004162421706

  虽然添加到TreeSet时,不使用equals方法,但在Comparable接口的API中有如下提醒:==当元素实现java.lang.Comparable接口重写compareTo方法时,也建议重写equals方法,应保证该方法与compareTo(Object obj)方法有一致的结果,如果两个对象通过equals方法比较返回true,则通过compareTo(Object obj)方法比较的返回值为0,否则结果会有点奇怪。==

1.3.2 定制排序

  如果放到TreeSet中的元素的自然排序规则不符合当前业务的排序需求,或者元素的类型没有实现Comparable接口,那么在创建TreeSet时,可以单独指定一个定制比较器Comparator的实现类对象。使用定制比较器的TreeSet判断两个元素相等的标准是通过compare(Object o1,Object o2)方法比较两个元素返回了0。

  示例代码:

  Teacher类示例代码:

public class Teacher {
    private int id;
    private String name;

    public Teacher(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Teacher{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

  测试类示例代码:

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

public class TreeSetTest3 {
    public static void main(String[] args) {
        TreeSet<Object> set = new TreeSet<>(new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                Teacher t1 = (Teacher) o1;
                Teacher t2 = (Teacher) o2;
                return t1.getId() - t2.getId();
            }
        });

        set.add(new Teacher(3,"张三"));
        set.add(new Teacher(1,"李四"));
        set.add(new Teacher(2,"王五"));
        set.add(new Teacher(3,"张三凤"));
        System.out.println("元素个数:"+set.size());
        for (Object o : set) {
            System.out.println(o);
        }
    }
}

image-20221004163008578

1.4 案例:企业面试题

  案例需求:通过键盘录入一串字符,去掉其中的重复字符,打印出不同的字符(重复的字符仅保留一份),必须保证输入顺序。例如,输入baaabbccacddd,打印结果为bacd。

示例代码:

import java.util.LinkedHashSet;
import java.util.Scanner;

public class SetExer {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        System.out.println("请输入一串字符:");
        String strings = input.next();

        LinkedHashSet<Object> set = new LinkedHashSet<>();
        char[] chars = strings.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            set.add(chars[i]);
        }

        String result="";
        for (Object o : set) {
            result+=o;
        }
        System.out.println("result="+result);


    }
}

image-20221004164522410

目录
相关文章
|
7天前
|
Dart
Dart之集合详解(List、Set、Map)
Dart之集合详解(List、Set、Map)
13 1
|
13天前
|
存储 JavaScript 前端开发
JavaScript进阶-Map与Set集合
【6月更文挑战第20天】JavaScript的ES6引入了`Map`和`Set`,它们是高效处理集合数据的工具。`Map`允许任何类型的键,提供唯一键值对;`Set`存储唯一值。使用`Map`时,注意键可以非字符串,用`has`检查键存在。`Set`常用于数组去重,如`[...new Set(array)]`。了解它们的高级应用,如结构转换和高效查询,能提升代码质量。别忘了`WeakMap`用于弱引用键,防止内存泄漏。实践使用以加深理解。
|
7天前
|
存储 消息中间件 算法
Java中的集合框架详解:List、Set、Map的使用场景
Java中的集合框架详解:List、Set、Map的使用场景
|
2天前
|
存储 安全 Java
详解Java中集合的List接口实现的ArrayList方法 | Set接口实现的HashSet方法
详解Java中集合的List接口实现的ArrayList方法 | Set接口实现的HashSet方法
|
21天前
|
存储 安全 Java
Java集合详解:Set, Map, Vector, List的对比与联系
Java集合框架核心包括List、Set、Map和Vector。List允许重复元素,如ArrayList(适合读取)和LinkedList(适合插入删除)。Set不允许重复,有HashSet(无序)和TreeSet(排序)。Map存储键值对,HashMap(无序)和TreeMap(排序)。Vector是线程安全的ArrayList替代品,但在多线程环境下使用。选择集合类型应根据应用场景,如有序、无序、键值对需求及线程安全考虑。
|
24天前
|
存储 安全 Java
Java 集合(List、Set、Map 等)相关问答归纳再整理
HashMap 中使用键对象来计算 hashcode 值 HashSet 使用成员对象来计算 hashcode 值,对于两个对象来说hashcode 可能相同,所以 equals() 方法用来判断对象的相等性,如果两个对象不同的话,那么返回 false。 HashMap 比较快,因为是使用唯一的键来获取对象,HashSet 较 HashMap 来说比较慢。 4.1.3 HashMap 与 TreeMap
13 2
|
25天前
|
存储 Java 索引
JavaSE——集合框架一(6/7)-Set系列集合:LinkedHashSet的底层原理、TreeSet集合(介绍,自定义排序规则,排序示例)
JavaSE——集合框架一(6/7)-Set系列集合:LinkedHashSet的底层原理、TreeSet集合(介绍,自定义排序规则,排序示例)
19 1
|
25天前
|
存储 Java 索引
JavaSE——集合框架一(5/7)-Set系列集合:Set集合的特点、底层原理、哈希表、去重复原理
JavaSE——集合框架一(5/7)-Set系列集合:Set集合的特点、底层原理、哈希表、去重复原理
30 1
|
6天前
|
存储 API Kotlin
Kotlin中的Set集合
Kotlin中的Set集合
7 0
|
27天前
|
存储 NoSQL Redis
Redis第七弹-Set与ZSET基本操作,Set(集合特点)SADD key member(注意这个key,必须是你自定义名字,不能用key)​编辑SMEMBERS key-查询所有的key
Redis第七弹-Set与ZSET基本操作,Set(集合特点)SADD key member(注意这个key,必须是你自定义名字,不能用key)​编辑SMEMBERS key-查询所有的key