六、Set接口

1、是什么

        collection的子接口,Set接口的实现类常用的有:HashSet、TreeSet和LinkedHashSet。特点有:不可重复

2、常用方法

        add(E e)如果set中尚未存在指定的元素,则添加此元素
        clear()移除此set中的所有元素
        contains(Object o)如果set包含指定的元素,则返回true
        isEmpty()如果set不包含元素,则返回true
        size()返回set中的元素数(其容量)

3、案例

package com.hg.Collection.Set;

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

public class SetTest {
    public static void main(String[] args) {
        Set<String> stringSet = new HashSet<>();
        stringSet.add("hello");
        stringSet.add("sister");
        stringSet.add("叶瞬光");
        stringSet.add("叶瞬光");

        for (String s : stringSet) {
            System.out.println(s);
        }

        System.out.println("长度为:" + stringSet.size());
        System.out.println("是否为空:" + stringSet.isEmpty());
        System.out.println("是否包含‘叶瞬光’:" + stringSet.contains("叶瞬光"));

        stringSet.clear();
        System.out.println(stringSet);
    }
}

4、HashSet类

数据结构:底层采用了哈希表,哈希表的本质就是“数组+链表”
        1.根据对象的哈希值计算(求余)存储位置,如果当前位置没有元素则直接存入;
        2.如果当前位置有,则拿当前的元素和已经存在的元素比较哈希值,如果哈希值不同,则将当前元素进行存储;
        3.如果哈希值相同则通过equals()方法比较两个元素的内容,如果内容不相同则将当前元素进行存储,如果内容相同则不存储当前元素。

案例:

package com.hg.Collection.Set.HashSet;

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

public class HashSetTest {
    public static void main(String[] args) {
        Set<Student> studentSet = new HashSet<>();

        studentSet.add(new Student("叶瞬光",18));
        studentSet.add(new Student("星见雅",18));
        studentSet.add(new Student("仪玄",18));
        studentSet.add(new Student("叶瞬光",18));
        //没有重写hashCode和equals前Set会重复
        //重写hashCode和equals后Set不会重复
        for (Student student : studentSet) {
            System.out.println(student);
        }
    }
}

class Student{
    private String name;
    private Integer age;

    public Student() {
    }

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

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;

        Student student = (Student) o;

        if (!name.equals(student.name)) return false;
        return age.equals(student.age);
    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + age.hashCode();
        return result;
    }
}

5、LinkedHashSet类

概述:

        LinkedHashSet是Set接口基于双向链表的实现,也是HashSet的子类。元素的存储和取出顺序是一致的。

数据结构:

        LinkedHashSet根据元素的hashCode值来决定元素的存储位置,使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的,如图:

LinkedHashSet的有序性本质是LinkedHashMap的特性,其核心逻辑简化如下:

案例:

package com.hg.Collection.Set.HashSet.LinkedHashSet;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

public class LinkedHashSetTest2 {
    public static void main(String[] args) {
        //1.初始化一个空的 LinkedHashSet<String>;
        Set<String> set = new LinkedHashSet<>();
        //2.依次添加姓名:"张三"、"李四"、"王五"、"张三"、"赵六";
        set.add("张三");
        set.add("李四");
        set.add("王五");
        set.add("张三");
        set.add("赵六");
        //3.遍历并输出当前集合中的所有姓名(验证去重和有序性);
        System.out.println("=============遍历==============");
        for (String s : set) {
            System.out.println(s);
        }
        //4.删除姓名 "李四",再次遍历输出;
        System.out.println("=============删除后“李四”遍历==============");
        set.remove("李四");
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()){
            String s = iterator.next();
            System.out.println(s);
        }
        //5.尝试删除不存在的姓名 "钱七",控制台打印 “删除结果:false”;
        boolean res = set.remove("钱七");
        System.out.println("删除结果:" + res);
        //6.清空集合,遍历并打印 “集合为空”。
        System.out.println("=============清空集合后遍历==============");
        set.clear();
        System.out.println("集合为空:" + set);

    }
}

6、TreeSet类

概述:

        TreeSet是Set接口基于红黑树的实现类;默认对元素进行自然排序;

数据结构:

/**
 * 二叉树的节点类
 * 用于描述二叉树中单个节点的结构,包含节点值、左子节点、右子节点
 */
public class TreeNode {
    // 当前节点存储的数值
    int val;
    // 当前节点的左子节点 引用(指针),默认为null
    TreeNode left;
    // 当前节点的右子节点 引用(指针),默认为null
    TreeNode right;

    /**
     * 二叉树节点的构造方法
     * @param x 传入的当前节点的数值
     */
    TreeNode(int x) {
        // 给当前节点的数值赋值
        val = x;
    }
}

7、Comparable接口

        TreeSet会调用集合元素的compareTo(Objectobj)方法来比较元素之间的大小关系,然后将集合元素按升序(默认情况)排列。

8、Comparator比较器

        如果元素所属的类没有实现Comparable接口,或不希望按照升序(默认情况)的方式排列元素或希望按照其它属性大小进行排序,则考虑使用定制排序。

6、7、8、案例:

package com.hg.Collection.Set.TreeSet;

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

public class TreeSetTest2 {
    public static void main(String[] args) {
        Set<Student> studentSet = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        studentSet.add(new Student("叶瞬光",18));
        studentSet.add(new Student("星见雅",19));
        studentSet.add(new Student("仪玄",20));
        for (Student student : studentSet) {
            System.out.println(student);
        }

    }
}

class Student /*implements Comparable<Student>*/{
    private String name;
    private Integer age;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

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

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

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐