<Java>集合——Set(HashSet,TreeSet,LinkedHashSet)

一、Set的介绍

Set是一个接口,存储无序的、不可重复的元素

其实现类有以下3个:

1、HashSet(常用)

  • 线程不安全的

  • 可存储null值

2、LinkedHashSet

  • 是HashSet的子类,由于是链表结构,遍历其内部数据时,可以按照添加的顺序读取

3、TreeSet

  • 可以按照添加对象的指定属性进行排序(实现Comparable或者是Comparator)

二、HashSet

1、特点

  • 不能保证元素的排列顺序
  • 不是线程安全
  • 集合元素可以是null

2、要求

  • 判断两个元素相等:两个对象通过hashCode()方法比较相等,并且两个对象通过equals()方法也比较相等
  • 对于存放在Set容器中的对象,对象的类一定要重写hashCode()和equals()方法。同时保证如果根据equals()方法,两个对象是相等的,那么在两个对象上调用hashCode()方法也必须生成相同的整数结果

3、构造方法

在这里插入图片描述

4、基本方法

在这里插入图片描述

示例:

Person类:

package SetPack;

public class Person {

    private String name;
    private int age;

    public Person() {};
    public Person(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 boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Person person = (Person) o;

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

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

主函数:

package SetPack;

import java.util.*;

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

        set.add(new Person("DaMing",18));
        set.add(new Person("LingLing",20));
        set.add(new Person("Zhangsan",50));
        set.add(new Person("LingLing",20));

        Iterator<Person> it=set.iterator();
        while(it.hasNext())
        {
            Person tmp=it.next();
            System.out.println(tmp.getName()+tmp.getAge());
        }
    }

}

在这里插入图片描述

由此看出,重写了hashCode()方法和equals()方法后,就能保证元素不重复了。

三、LinkedHashSet

1、特点

  • LinkedHashSet是由可预知迭代顺序的Set接口的哈希表和链接列表实现。此链接列表定义了迭代顺序,即按照元素插入到集合中的顺序进行迭代。
  • 需要注意的是,插入顺序不受在集合中重新插入的元素的影响。(如果在 s.contains(e) 返回 true 后立即调用 s.add(e),则元素 e 会被重新插入到集合 s 中。)

2、构造方法

在这里插入图片描述

3、基本方法

在这里插入图片描述

示例:

package SetPack;

import java.util.*;

public class LinkedHashSetDemo {
    public static void main(String[] args) {
        Set<Person> set=new HashSet<>();

        set.add(new Person("DaMing",18));
        set.add(new Person("LingLing",20));
        set.add(new Person("Zhangsan",50));
        set.add(new Person("LingLing",20));
        System.out.println("--------------------------------------输出HashSet--------------------------------------------");
        Iterator<Person> it=set.iterator();
        while(it.hasNext())
        {
            Person tmp=it.next();
            System.out.println(tmp.getName()+tmp.getAge());
        }

        Set<Person> LinkedSet=new LinkedHashSet<>();
        LinkedSet.add(new Person("DaMing",18));
        LinkedSet.add(new Person("LingLing",20));
        LinkedSet.add(new Person("Zhangsan",50));
        LinkedSet.add(new Person("LingLing",20));
        System.out.println("---------------------------------------输出LinkedHashSet--------------------------------------");
        Iterator<Person> it2=LinkedSet.iterator();
        while(it2.hasNext())
        {
            Person tmp=it2.next();
            System.out.println(tmp.getName()+tmp.getAge());
        }
    }
}

运行结果:
在这里插入图片描述
可以看到,LinkedHashSet的输出顺序和插入的顺序是一样的,并且在最后依次执行LinkedSet.add(new Person("LingLing",20));语句也并没有改变它插入的位置,即插入顺序不受在集合中重新插入的元素的影响。

虽然输出顺序和插入顺序一致,但是仍然不能说LinkedHashSet是有序的,因为存储到内存中时,是根据某一个hash函数确定插入的位置,因此在内存中数据的顺序是无序的,在这里只是输出顺序和插入顺序一致,不能说明其就是有序的。因此判断是否有序,是根据其在内存中是否有序。

四、TreeSet

TreeSet类保证排序后的 set 按照升序排列元素,根据使用的构造方法不同,可能会按照元素的自然顺序 进行排序(参见 Comparable),或按照在创建 set 时所提供的比较器(Comparator)进行排序。

  • 比较两个对象是否相同的标准看的是实现的比较器返回值,如果返回0,则不插入。

1、实现了Comparable的TreeSet

示例:

package SetPack;

import java.util.*;
public class TreeSetDemo {
    public static void main(String[] args) {
        Set<Integer> treeset=new TreeSet<>();
        treeset.add(3);
        treeset.add(30);
        treeset.add(13);
        treeset.add(5);
        treeset.add(9);

        System.out.println("输出数据元素为Integer类型时的TreeSet:");
        Iterator<Integer> it=treeset.iterator();
        while(it.hasNext())
        {
            System.out.print(it.next()+"\t");
        }
        System.out.println();

        //需要重写Comparable接口
        Set<Person> setPerson=new TreeSet<>();
        setPerson.add(new Person("Daming",18));
        setPerson.add(new Person("Ali",16));
        setPerson.add(new Person("Ben",19));
        setPerson.add(new Person("Betty",15));
        setPerson.add(new Person("Tom",26));
        setPerson.add(new Person("Jim",23));
        setPerson.add(new Person("Jim",32));
        setPerson.add(new Person("Jim",32));
        System.out.println("输出数据元素为Person类型时的TreeSet:");
        Iterator<Person> it2=setPerson.iterator();
        while(it2.hasNext())
        {
            Person tmp=it2.next();
            //重写toString方法
            System.out.println(tmp.toString());
        }
    }
}

Comparable接口的实现如下:

    @Override
    public int compareTo(Person o) {
        int res=this.name.compareTo(((Person)o).name);
        if(res!=0)
        {
            return res;
        }

        return this.age-((Person)o).age;
    }

先按照姓名从小到达排序,姓名相同再按照年龄从小到大排序。

运行结果:
在这里插入图片描述

2、实现Comparator的TreeSet

示例:

package SetPack;

import java.util.*;
public class TreeSetDemo2 {
    public static void main(String[] args) {

        Comparator com=new Comparator<Person>(){
            public int compare(Person p1,Person p2)
            {
                if(p1.getAge()-p2.getAge()!=0)
                {
                    return p1.getAge()-p2.getAge();
                }
                else
                {
                    return p1.getName().compareTo(p2.getName());
                }
            }
        };

        Set<Person> setPerson=new TreeSet<>(com);
        setPerson.add(new Person("Daming",18));
        setPerson.add(new Person("Ali",16));
        setPerson.add(new Person("Ben",19));
        setPerson.add(new Person("Betty",15));
        setPerson.add(new Person("Tom",26));
        setPerson.add(new Person("Jim",23));
        setPerson.add(new Person("Jim",32));
        setPerson.add(new Person("Jim",32));
        System.out.println("输出数据元素为Person类型时的TreeSet:");
        Iterator<Person> it2=setPerson.iterator();
        while(it2.hasNext())
        {
            Person tmp=it2.next();
            //重写toString方法
            System.out.println(tmp.toString());
        }
    }
}

Comparator的实现:

        Comparator com=new Comparator<Person>(){
            public int compare(Person p1,Person p2)
            {
                if(p1.getAge()-p2.getAge()!=0)
                {
                    return p1.getAge()-p2.getAge();
                }
                else
                {
                    return p1.getName().compareTo(p2.getName());
                }
            }
        };

先按照年龄从小到大,年龄相同则按照姓名从小到大

运行结果:
在这里插入图片描述

在这里,同时在Person也实现了Comparable接口。但是由于
Set<Person> setPerson=new TreeSet<>(com);,将Comparator的实现写到了参数里,因此是按照Comparator的规则来排序。

PS:此为学习笔记,如有错误,请友好指正,感谢。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值