【Java 集合:Set集合+案例分析】

Set集合

想要学习其他关于Java集合知识,查看我上期博客:Collection集合List集合

Set集合概述:

Set 接口是 Collection 的子接口,set 接口没有提供额外的方法

Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。

Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals() 方法进行判断

Set 存储是无序的、不可存储重复的数据。

Set集合特点:

  1. 特点:无序,不重复

  2. 遍历:foreach,迭代器

  3. 扩容: 初始容量16,负载因子0.75,扩容增量1倍

Set集合中的实现类:

HashSet实现类:

HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取、查找、删除性能。

HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。

对于存放在 Set 容器中的对象,对应的类一定要重写 equals() 和 hashCode(Object obj) 方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”。

HashSet 具有以下特点:

不能保证元素的排列顺序

HashSet 不是线程安全的

集合元素可以是 null

案例:

public class Demo1 {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        //set集合存储的无序的  不可重复的
        set.add("b");
        set.add("a");
        set.add("d");
        set.add("c");
        set.add("a");
        set.add("ad");
        System.out.println(set);

        Set<Integer> set1 = new HashSet<>();
        set1.add(78);
        set1.add(23);
        set1.add(100);
        set1.add(56);
        System.out.println(set1);
        set1.remove(23);
        //循环
        for (Integer integer : set1) {
            System.out.println(integer);
        }

    }
}
HashSet集合中存对象:

案例:

class Person {
    int id;
    String name;

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

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

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

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
public class Demo2 {
    public static void main(String[] args) {
        Person person1 = new Person(1, "张三");
        Person person2 = new Person(1, "李四");
        Person person3 = new Person(1, "李四");
        Person person4 = new Person(1, "李四");
        //只能存入一个内容相同的数据
        //所以就要 用到 equals 和 hashCode
        Set<Person> set = new HashSet<>();
        //在调用add方法的时候 底层在调用hashCode方法和equals
        set.add(person1);
        set.add(person2);
        set.add(person3);
        set.add(person4);
        System.out.println(set);
    }
}

重写 hashCode() 方法:

在程序运行时,同一个对象多次调用 hashCode() 方法应该返回相同的值。
当两个对象的 equals() 方法比较返回 true 时,这两个对象的 hashCode() 方法的返回值也应相等。
对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值。

重写equals()方法:

当一个类有自己特有的“逻辑相等”概念,当改写 equals() 的时候,总是要改写 hashCode(),根据一个类的 equals 方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据 Object.hashCode() 方法,它们仅仅是两个对象。

总之在重写equals方法,就必须重写hashCode方法。

TreeSet实现类:

一个包含有序的且没有重复元素的集合

作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序

TreeSet是基于TreeMap实现的

TreeSet中的新增的方法:

Comparator comparator()
Object first()
Object last()
Object lower(Object e)
Object higher(Object e)
SortedSet subSet(fromElement, toElement)
SortedSet headSet(toElement)
SortedSet tailSet(fromElement)

public class Demo1 {
    public static void main(String[] args) {
        //TreeSet在存储的数据的时候 会排序
        Set<Integer> set = new TreeSet<>();
        set.add(89);
        set.add(79);
        set.add(69);
        set.add(109);
        set.add(39);
        System.out.println(set);

        Set<String> set1 = new TreeSet<>();
        set1.add("d");
        set1.add("w");
        set1.add("a");
        set1.add("c");
        System.out.println(set1);
    }
}

TreeSet中的排序的原因分为自然排序和定制排序(存入对象):

定制排序:

TreeSet 的自然排序要求元素所属的类实现 Comparable 接口,如果元素所属的类没有实现Comparable 接口,或不希望按照升序(默认情况)的方式排列元素或希望按照其它属性大小进行排序,则考虑使用定制排序。定制排序,通过 Comparator 接口来实现。需要重写 compare(T o1,T o2) 方法。

利用 int compare(T o1,T o2) 方法,比较 o1 和 o2 的大小:如果方法返回正整数,则表示 o1 大于 o2;如果返回 0,表示相等;返回负整数,表示 o1 小于 o2。
要实现定制排序,需要将实现 Comparator 接口的实例作为形参传递给 TreeSet 的构造器。

此时,仍然只能向 TreeSet 中添加类型相同的对象。否则发生 ClassCastException 异常。

使用定制排序判断两个元素相等的标准是:通过 Comparator 比较两个元素返回了 0。
案例:

class Student implements Comparable<Student>{
    String name;
    int age;

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

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

    @Override
    public int compareTo(Student o) {
        System.out.println("123");
        int num = this.age - o.age;
        return num;
    }
}
public class Demo2 {
    public static void main(String[] args) {
        Student stu1 = new Student("老邢", 45);
        Student stu2 = new Student("老邢", 35);
        Student stu3 = new Student("saolei", 25);
        Student stu4 = new Student("老万", 87);
        //按照年龄进行排序 存到TreeSet集合中
        Set<Student> set = new TreeSet<>();
        set.add(stu1);
        set.add(stu2);
        set.add(stu3);
        set.add(stu4);
        System.out.println(set);
    }
}

总结:

1.HashSet存对象的时候,一定在类中重写equals和hashCode方法

2.TreeSet存对象的时候,一定要实现一个接口Comparable,重写compareTo方法
比较两个对象某个属性的int类型差值

3.equals ,hashCode 都是Object类中的方法,子类都重写了该些方法

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值