Set接口及其实现类

概述

Set接口同List接口一样,继承自Collection接口,与Collection中方法基本一致。与List接口不同的是,Set接口中元素无序,元素不重复。

Set接口的两个实现类

HashSet集合

基于HashMap存储,HashSet根据对象的哈希值确定集合中的储存位置,因此具有良好的存取和查找性能。

HashSet代码示例如下:

        HashSet<String> set = new HashSet<>();
        set.add("Data_1");
        set.add("Data_2");
        set.add("Data_3");
        set.add("Data_3");

        //创建iterator对象
        Iterator<String> it = set.iterator();
        while (it.hasNext()){
            String str = it.next();
            System.out.println(str);
        }

运行结果如下:

Data_3
Data_1
Data_2

从打印结果可以看出,

取出元素的顺序与添加元素的顺序不一致,说明Set接口无序。重复存入的字符串对象"Data_3"被去除了,只添加了一次。说明Set接口没有重复元素。

HashSet集合之所以能确保不出现重复元素,因为存入元素时做了很多操作,调用HashSet集合时,

  1. 当前存入对象的hashCode()方法获得对象的哈希值,根据对象的哈希值计算出一个存储位置。
  2. 如果该位置上没有元素,则直接将元素存入。如果该位置上有元素存在,则会调用equals()方法让当前存入的元素一次和该位置上的元素进行比较,如果返回false就存入集合,如果返回true说明有重复元素,舍弃该元素。

HashSet存入对象元素的注意事项
根据前面的分析不难看出,当向集合中存入元素时,为了保证HashSet正常工作,要求在存入对象时,重写Object类中的hashCode()和equals()方法。
先创建一个类,具体代码示例如下:

    String id;
    String name;

    public Teacher(){}

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

    public String toString(){
        return id + ":" + name;
    }

测试类代码如下:

public class Test {

    public static void main(String[] args){
        HashSet hs = new HashSet<>();
        Teacher t1 = new Teacher("1", "Jack");
        Teacher t2 = new Teacher("1", "Jack");
        Teacher t3 = new Teacher("2", "Rose");

        hs.add(t1);
        hs.add(t2);
        hs.add(t3);

        System.out.println(hs);
    }
}

运行结果如下所示:

[1:Jack, 2:Rose, 1:Jack]

由结果我们看出HashSet类型的数据中出现了两个相同的元素。之所以没去掉这样的重复元素,

因为定义Student类时没有重写hashCode()和equals()方法。

下面我们在Teacher类中重写这hashCode()和equals()方法:

public class Teacher {
    String id;
    String name;

    public Teacher(){}

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

    //重写toString()方法
    public String toString(){
        return id + ":" + name;
    }

    //重写hashCode()方法
    public int hashCode(){
        return id.hashCode();
    }

    //重写equals方法
    public boolean equals(Object obj){
        //同一个对象返回true
        if (this == obj)
            return true;

        //对象为空返回false
        if (obj == null)
            return false;

        //如果obj为Teacher类型
        if (obj instanceof Teacher){
            //判断值是否相同
            Teacher t = (Teacher) obj;
            if (this.id.equals(t.id) && this.name.equals(t.name)){
                return true;
            }
        }
        return true;
    }
}

由上述代码看出,在hashCode()方法中返回id属性的哈希值,在equals()方法中比较对象的id属性是否相等,并返回结果。

TreeSet集合

基于TreeMap实现,有序的、不含有重复元素的集合。

代码演示如下:

        TreeSet<String> ts = new TreeSet<>();
        ts.add("B");
        ts.add("D");
        ts.add("A");
        ts.add("C");
        
        System.out.println(ts);

运行结果如下:

[A, B, C, D]

由结果可以看出,TreeSet并不是按照存入的顺序存储,也不是无序存储,而是根据字母顺序进行排序的存储。

使用treeSet存储对象类型的元素
先创建对象,代码如下:

public class Teacher {
    int id;
    String name;

    public Teacher(){}

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

    //重写toString()方法
    public String toString(){
        return id + ":" + name;
    }
}

程序入口代码如下:

    public static void main(String[] args){
        TreeSet<Teacher> ts = new TreeSet<>();
        Teacher t1 = new Teacher("1", "Jack");
        Teacher t2 = new Teacher("2", "Rose");
        Teacher t3 = new Teacher("3", "Sam");
        ts.add(t1);
        ts.add(t2);
        ts.add(t3);
        System.out.println(ts);
    }

运行结果如下:

之所以报出这样的错误,

因为JDK不知到怎么去对Teacher对象排序,Teacher类必须实现排序接口Comparable才能作为TreeSet的元素存储。

posted on 2021-10-17 17:34  技术小伙伴  阅读(320)  评论(0)    收藏  举报