JavaSE——集合(四)Collection的子接口set

1、Set结构

1.1、set的性质

在这里插入图片描述
set中没有额外定义新的方法,使用的都是Collection中声明过的方法

一、Set:存储的无序性,不可重复的数据
以HashSet为例
1、无序性不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值进行添加
2、不可重复性,保证添加的元素按照equals()判断时,不能返回true。

2、HashSet

二、添加元素的过程
我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值通过散列函数计算出在HashSet底层数组中的存放位置(索引位置),判断数组此位置上是否已经有元素:
没有其他元素则直接添加元素a
有元素b或不止一个则比较元素a与元素b的hash值,若hash值不相同,则直接添加a;若hash值相同,调用a的equals方法进行值的比较,若已经存在则不能添加。
若添加成功,在jdk7中,新加入的元素放在数组中指向旧元素,jdk8反过来。

在这里插入图片描述

2.1、重写hashCode()方法

  1. 不重写hashCode()的情况
public class test {

    public static void main(String[] args) {
        HashSet a = new HashSet();
        a.add(1);
        a.add(new People("dcd",20));
        a.add(new People("dcd",20));
        Iterator it = a.iterator();
        while(it.hasNext()){
            System.out.println(it.next()+" ");
        }
    }
}


class People{
    String name;
    int age;
    People(){}
    People(String n,int a){
        name=n;
        age=a;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        People people = (People) o;
        return age == people.age && Objects.equals(name, people.name);
    }

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

在这里插入图片描述

可以发现并没有去除相同的对象,因为对于自定义的类来说,默认生成的是Object.hashCode(),此哈希值具有随机性,就会导致两个内容相同的对象分在了不同的位置上面,就造成了这样的结果,解决这种问题,就需要重写hashCode()方法,注意要和equals()方法一块儿写。

  1. 重写后的输出
import java.util.*;

public class test {

    public static void main(String[] args) {
        HashSet a = new HashSet();
        a.add(1);
        a.add(new People("dcd",20));
        a.add(new People("dcd",20));
        Iterator it = a.iterator();
        while(it.hasNext()){
            System.out.println(it.next()+" ");
        }
    }
}


class People{
    String name;
    int age;
    People(){}
    People(String n,int a){
        name=n;
        age=a;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        People people = (People) o;
        return age == people.age && Objects.equals(name, people.name);
    }

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

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

在这里插入图片描述

  1. hashCode()重写的源代码

在这里插入图片描述

在这里插入图片描述

3、LinkedHashSet

无序体现在存放的时候依然是按照hash值去存放的,LinkedHashSet能够按照添加的顺序输出的原因是使用双向链表实现的。
对于频繁的遍历操作,效率比HashSet要高。

4、TreeSet

向TreeSet中添加的数据,要求是相同类的对象,不能添加不同类的对象,底层是一个红黑树

在这里插入图片描述

  1. 正常数据可以自动排序
public class test {

    public static void main(String[] args) {
        TreeSet a = new TreeSet();
        a.add(1);
        a.add(8);
        a.add(-1);
        Iterator it = a.iterator();
        while(it.hasNext()){
            System.out.println(it.next()+" ");
        }
    }
}//-1 1 8
  1. 自定义类如果不进行comparable的重写是无法进行排序的。TreeSet不会调用equals函数的,他会调用Comparable进行比较,需要注意。

自然排序

import java.util.*;

public class test {

    public static void main(String[] args) {
        TreeSet a = new TreeSet();
        a.add(new People("Tom",20));
        a.add(new People("Tom",18));
        Iterator it = a.iterator();
        while(it.hasNext()){
            System.out.println(it.next()+" ");
        }
    }
}


class People implements Comparable{
    String name;
    int age;
    People(){}
    People(String n,int a){
        name=n;
        age=a;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        People people = (People) o;
        return age == people.age && Objects.equals(name, people.name);
    }

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

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


    @Override
    public int compareTo(Object o) {
        if(o instanceof People){
            People p=(People) o;
            if(this.name.compareTo(p.name)!=0) return this.name.compareTo(p.name);
            else return Integer.compare(this.age,p.age);
        }else throw new RuntimeException("输入错误");
    }
}

定制排序

public class test {

    public static void main(String[] args) {
        Comparator com=new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if(o1 instanceof People&&o2 instanceof People){
                    People a=(People) o1;
                    People b=(People) o2;
                    if(a.name.compareTo(b.name)!=0) return a.name.compareTo(b.name);
                    else return Integer.compare(a.age,b.age);
                }else throw new RuntimeException("输入错误");
            }
        };
        TreeSet a = new TreeSet();
        a.add(new People("Tom",20));
        a.add(new People("Tom",18));
        Iterator it = a.iterator();
        while(it.hasNext()){
            System.out.println(it.next()+" ");
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值