2021-07-02笔记

Set接口介绍

Set接口继承自Collection,Set接口中没有新增方法,方法和Collection保持完全一致。我们在前面通过List学习的方法,在Set中用法相同。

【特点】

无序、不可重复。

  • 无序指Set中的元素没有索引,只能遍历查找;

  • 不可重复指不允许加入重复的元素,如果要加入的新元素和Set中某个元素通过equals()方法对比为true,则不予加入

Set常用的实现类有:【HashSet】、【TreeSet】等,我们一般使用HashSet

HashSet容器类
  • 没有重复元素的集合,不保证元素顺序

  • HashSet允许有nul元素。HashSet是采用哈希算法实现,底层实际是HashMap实现的(HashSet本质就是一个简化版的HashMap),查询效率和增删效率都比较高

  • Hash算法也称之为散列算法:通过对哈希值进行模运算分散存放元素

【没有厕所的图书馆 张三 放身份证的带有一排格子的盒子】

HashSet的使用

for-each循环的优点:简洁,不同循环中可用相同名称的元素来进行

//实例化HashSet
        Set<String> set = new HashSet<>();

        //添加元素
        set.add("a");
        set.add("b1");
        set.add("c2");
		set.add("");
        set.add("d");
        set.add("a");

        //获取元素,Set容器中没有索引,没有get(int index)方法,所以使用foreach循环;
		允许有null元素,但不允许有重复元素
        for (String str:set){
            System.out.println(str);
        }

        //删除元素
        boolean flag = set.remove("c2");
        System.out.println(flag);
        for (String str:set){
            System.out.println(str);
        }

        //查询元素个数
        int size = set.size();
        System.out.println(size);
HashSet存储特征分析
  • HashSet是一个不保证元素顺序且没有重复元素的集合,是线程不安全的
  • HashSet允许有null元素

【无序】

在HashSet 的底层是使用HashMap存储元素的。HashMap底层使用的是数组与链表实现元素的存储。元素在数组中存放时,并不是有序

存放的也不是随机存放的,而是对元素的哈希值进行运算决定元素在数组中的位置

【不重复】

  • 当两个元素的哈希值进行模运算后得到相同的结果,则它们在数组中的位置相同,此时会调用元素的equals()方法判断两个元素是否相同,若相同则不放入后者;若不同,按照先后顺序一个个单向链接
  • 默认模运算以16进行,容器默认格子有16个
  • 元素放在节点中,节点放在数组中,节点单链连接
  • 对比顺序:哈希值—哈希值模运算的结果—元素本身
通过HashSet存储自定义对象!!!
//实例化HashSet
        Set<Users> set1 = new HashSet<>();

        Users u1 = new Users("cyf",26);
        Users u2 = new Users("cyf",26);

        set1.add(u1);
        set1.add(u2);

        System.out.println(u1.hashCode());//460141958
        System.out.println(u2.hashCode());//1163157884

        /**
         *  为什么会有”看似出现重复元素“的现象?
         *  是因为此处放入的元素是u1、u2(的地址),放入时根据u1、u2的hashcode判别
         *  并不是放入u1、u2所包含的信息
         *
         *  如果通过重写hashcode()方法去比较u1、u2所包含信息本身的哈希值,肯定会判断相同,则不会放入u2!!!
         *
         *  所以可以通过重写hashcode()方法达到是否允许放入重复内容的目的
         */
        for (Users users:set1){
            System.out.println(users);
        }

HashSet底层源码分析/P210

TreeSet容器类

  • TreeSet是一个支持排序的容器。底层实际是用TreeMap 实现的,内部维持了一个简化版的TreeMap,通过 key来存储Set的元素。

  • TreeSet内部需要对存储的元素进行排序,【我们需要给定排序规则】

  • 排序规则实现方式:

通过元素自身实现比较规则

通过比较器指定比较规则

TreeSet的使用
public static void main(String[] args) {
        //实例化TreeSet
        Set<String> set = new TreeSet<>();
        //添加元素,如无排序规则,需要先给定排序规则
        set.add("c");
        set.add("a");
        set.add("d");
        set.add("b");
        set.add("a");

        //获取元素
        for (String str:set){
            System.out.println(str);
        }
    }
通过元素自身实现排序规则
//实例化TreeSet
        Set<String> set = new TreeSet<>();
        //添加元素,如无排序规则,需要先给定排序规则
        set.add("c");
        set.add("a");
        set.add("d");
        set.add("b");
        set.add("a");

        //获取元素
        for (String str:set){
            System.out.println(str);
        }

        System.out.println("---------------------------");

        Set<Users> set1 = new TreeSet<>();
        Users u1 = new Users("wd",6);
        Users u2 = new Users("whh",18);
        Users u3 = new Users("awa",18);

        set1.add(u1);
        set1.add(u2);
        set1.add(u3);

        /**
         * users cannot be cast to java.lang.Comparable
         * 无法比较,无法排序
         *
         * 通过给Users类实现Comparable类,重写comparableTo方法,给定排序规则
         * 先按年龄排,年龄相同的再按名字排
         */
        for (Users users:set1){
            System.out.println(users);
        }
通过比较器指定比较规则
  • 通过比较器定义比较规则时,需单独创建一个比较器,比较器需要实现Comparator接口中的compare方法来定义比较规则。在【实

例化TreeSet 】时将比较器对象交给TreeSet来完成元素的排序处理。此时元素自身就不需要实现比较规则了。

  • 在main方法内,不能再定义私有的成员变量

为什么我觉得设置只比较年龄,它自动比较了姓名???

public class StudentComparator implements Comparator<Student> {

    //定义比较规则
    @Override
    public int compare(Student o1, Student o2) {
        if (o1.getAge() > o2.getAge()){
            return 1;
        }
        if (o1.getAge() == o2.getAge()){
            return o1.getName().compareTo(o2.getName());
        }
        return -1;
    }
}
//在实例化TreeSet时将传递外部比较器,不依赖元素而独立存在
        Set<Student> set2 = new TreeSet<>(new StudentComparator());
        Student s1 = new Student("wbc",18);
        Student s2 = new Student("qaq",22);
        Student s3 = new Student("dwg",22);
        Student s4 = new Student("wbc",20);

        set2.add(s1);
        set2.add(s2);
        set2.add(s3);
        set2.add(s4);

        for (Student s:set2){
            System.out.println(s);
        }

单例集合使用案例

使用List类型容器实现
package com.cyf;
/**
 * 需求:
 * 产生1-10之间的随机数([1,10]闭区间),将不重复的10个随机数放到容器中
 * 要求使用List类型容器实现
 */

import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    public static void main(String[] args) {

        List<Integer> list = new ArrayList<>();

        while(true){
            //产生足够多的随机数
            int num = (int)(Math.random()*10+1);
            //判断当前元素在容器中是否存在,如果不存在就添加,存在就重新随机
            if (!list.contains(num)){
                list.add(num);
            }
            //结束循环,直到存够10个数即停止
            if (list.size() == 10){
                break;
            }
        }

        for (Integer i:list){
            System.out.println(i);
        }
    }
}
使用Set类型容器实现
package com.cyf;
/**
 * 需求:
 * 产生1-10之间的随机数([1,10]闭区间),将不重复的10个随机数放到容器中
 * 要求使用Set类型容器实现
 */
import java.util.HashSet;
import java.util.Set;

public class SetDemo {
    public static void main(String[] args) {

        Set<Integer> set = new HashSet<>();
        while(true){
            int num = (int)(Math.random()*10+1);
            //将元素添加到容器中,Set容器不允许重复,所以不需判断
            set.add(num);

            //结束循环
            if (set.size() == 10){
                break;
            }
        }

        /*
        假排序现象!!!
        HashSet不支持排序,TreeSet支持排序
        为什么输出结果是自动排好序的?
        整型的hashcode就是返回了value,按hashCode模运算的结果放入元素,并不是经过排序,碰巧
            public static int hashCode(int value){
            return value;
        }
        hashCode(value)%16
         */
        for (Integer i: set){
            System.out.println(i);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值