Set集合

一. ArrayList嵌套

1.定义

在集合中存放集合,和二维数组类似

2.演示

public static void main(String[] args) {

    //集合中的元素还是集合

    ArrayList> school = new ArrayList<>();

    ArrayList clas1 = new ArrayList<>();

    clas1.add(new Student("小红",18));

    clas1.add(new Student("小明",20));

    school.add(clas1);

    ArrayList clas2 = new ArrayList<>();

    clas2.add(new Student("小张",18));

    clas2.add(new Student("小李",20));

    school.add(clas2);

    ArrayList clas3 = new ArrayList<>();

    clas3.add(new Student("tom",18));

    clas3.add(new Student("jack",20));

    school.add(clas3);


    System.out.println(school);

}



二. Set集合

1.定义

Set词义:数学中集合的概念。也是Collection的子接口。

Set作为Collection集合的子接口,没有新增的功能。但是有自己的存储特点。

Set集合存数的元素是无序的, 而且不允许储存重复的元素, 每当有新的元素存入的时候,Set集合会先去过滤, 如果发现和集合中现有元素出现重复,不在允许添加

2.应用场景

当我们不想让集合中出现重复的元素时,使用Set集合

当我们需要排除重复数据时,使用Set集合

3.演示

public static void main(String[] args) {

    //集合中的元素还是集合

    HashSet s = new HashSet<>();

    Student student = new Student("小红",18);

    Student student2 = new Student("小红",18);

    s.add(student);

    s.add(student2);

    Iterator it = s.iterator();

    while(it.hasNext()) {

        Student student3=it.next();

        System.out.println(student3);

    }

}


三. HashSet

1.定义

Set接口的一个具体的实现类。

底层是由哈希表实现。它不保证迭代的顺序。特别是不保证顺序一直不变。

HashSet集合中的元素是通过hash值比较是否相同

集合通过元素的hashCodeequals方法来比较两个元素是否相同, 不同就存入, 相同不存入

元素存入的位置未知,和存入的顺序无关

2.存储原理

HashSet最后还是存入数组中, 只是根据元素的Hash值来确定存入的角标位置

元素的hash值 ^ (元素的hash值 >>> 16) & (数组的长度-1)

HashSet中不是直接存入我们给定的元素, 而是用集合中的一个内部类封装我们存入的元素,所以当我们存入null的时候,不会因为和数组中角标位上默认值null起冲突

如果两个不同的元素根据不同的Hash值计算出了同一个角标值,那么都能存进去

3.构造方法

HashSet()    构造出一个新的集合, 底层数组默认的初始容量是16(扩容一倍),加载因子是0.75

加载因子: 集合中的数组可用的

角标值得可选范围越小,计算出重复角标值得概率就越高

HashSet(Collection c) 构造一个包含指定collection中元素的新set 

4.常用方法

boolean add( E e)    如果此set集合中尚未包含指定元素,则添加指定元素

boolean remove(Object o)    移除某个元素 []

int size()    获取集合的长度

5.重点重点重点!!!HashSet集合去重的流程

step1:先获取对象的hashCode,对象的哈希值不同直接存储到HashSet容器中。

step2:如果哈希值相同调用equals()比较。

true:认为是相同的元素,不存储

false:不同的元素,存储

原则:hashCode()和equals()的原则:

重写hashCode()的规则:自己生成hashCode值。公式

对象相同:属性值相同。那么哈希码必须相同。

对象不同:属性值不同。哈希码也可能相同。

重写equals()的原则:"权威的"

如果两个对象的属性值相同,认为是相同的对象,返回true。

如果两个对象的属性值有不同,就不是相同的对象,返回false。

结论:如果想使用HashSet集合,那么必须同时重写对象的hashCode()和equals()这两个方法。


重写的规则:

hashCode()

对象相同,属性值相同。哈希码必须相同。

对象不同,属性值不同。哈希码可能相同。

equals()

对象相同:属性值相同。必须true。

对象不同:属性值不同。必须false。

6.演示

需求: 去除ArrayList集合中的重复元素

public static void main(String[] args) {

    ArrayList al = new ArrayList<>();

    al.add("a");

    al.add("s");

    al.add("x");

    al.add("a");

    al.add("s");

    HashSet hs = new HashSet<>(al);

    System.out.println(hs);

}

7.测试题

需求: 创建Student类, 定义name和age属性, 创建多个对象(有属性重复的对象)存入ArrayList集合中, 然后对集合中的元素去重


四. HashSet集合中元素保证唯一性

1.原理解析

HashMap是通过调用元素的hashCode方法来比较两个元素是否形同的,所有如果要保证引用数据类型逻辑上的唯一性,就必须重写hashCode方法和equals方法

2.演示

public int hashCode() {

    final int prime = 31;

    int result = 1;

    result = prime * result + age;

    result = prime * result + ((name == null) ? 0 : name.hashCode());

    return result;

}

prime = 31 的原因

    别人选的, 没有原因

    是质数, 和别的值计算得出的数重复的概率低

    大小适中, 不会出现太大导致结果无法使用的问题

    便于计算 2<<5 -1

3.引用数据类型除重

重写hashCode和equals方法,自定义比较内容

4.测试题

需求: 编写程序, 获取10个1到20的随机数, 要求随机数不能重复, 打印结果

public static void main(String[] args) {

    Random random = new Random();

    HashSet hashSet = new HashSet<>();

    while(hashSet.size()<10){

        int num = random.nextInt(20)+1;

        hashSet.add(num);

    }

    System.out.println(hashSet);

}

5.测试题

需求: 从键盘录入一行数据, 去掉其中重复的字符,打印结果

6.测试题

产生10个随机的字符串, 要求不能重复(字符串中的字符取值在 'a' 到 'z' , 'A' 到 'Z' ,'0' 到 '9'),字符串的长度1-20


五. LinkedHashSet

1.定义

兼顾了linked的有序性和HashSet的元素唯一性

2.演示




六. TreeSet集合

1.定义

TreeSet是一种顺序的集合, 记住, 这里的顺序是指集合中的元素有顺序, 她是通过比较元素的大小来存放的, 大的存右边,小的存左边

默认的规则:Comparable接口,定义排序的规则。

存入的元素必须实现Comparable接口,并且重写comparTo方法(注:重写的方法应在该元素的类中,而不是测试类中重写

java.lang.Comparable接口的用途:强行对实现类的对象进行排序。

compareTo()-->此方法用于排序,返回值int类型

o1.compareTo(o2)-->int

    正数:o1 > o2,将o1排在o2的后面

    负数:o1 < o2,将o1排在o2的前面

    零:认为o1和o2相同不存储了。

最后存入的元素会形成一个树状结构

扩展内容:

红黑树--->平衡二叉树--->二叉树--->树

想了解平衡二叉树,可以参照此网址:https://baijiahao.baidu.com/s?id=1651427207567199156&wfr=spider&for=pc

2.构造方法

TreeSet()    构造一个新的空set, 该set根据其元素的自然顺序进行排序

TreeSet(Comparator comparator)  构建一个空的TreeSet, 他根据指定比较器进行排序

3.常用方法

add(E e)    将指定元素添加到此set

first()    返回此set中当前第一元素

last()    返回此set中当前最后一个元素

floor()    返回此set中小于等于给定元素的最大元素,不存在则返回null

higher()    返回此set中严格大于给定元素的最小元素,不存在则返回null

5.添加原理

TreeSet会将第一个添加的元素作为中点, 以后添加的元素会先跟中点进行比较, 如果大于就接着跟所比较元素的右边的元素接着比较,如果小于就接着跟所比较元素左边的元素接着比较, 直到无法找到可比较的元素,就会将新添加的这个元素放到当前位置

6.Comparable接口(默认的比较器)

java.lang.Comparable接口

java.lang.Comparable接口的用途:强行对实现类的对象进行排序。

仅有唯一的一个方法:compareTo()-->此方法用于排序,返回值int类型类型

o1.compareTo(o2)-->int    (从小到大排序)

    正数:o1 > o2,将o1排在o2的后面。

    负数:o1 < o2,将o1排在o2的前面。

    零:认为o1和o2相同,不存储了。

默认的TreeSet集合,使用的是Comparable接口,来给对象进行排序。以及去重。

所有存入的元素在比较的时候,如果集合没有比较器, 就会将元素本身转成Comparator类型并调用comparTo方法进行比较, 所以我们必须实现Comparato接口,并重写comparTo方法

7.Comparator比较器(自定义的比较器)

这是一个接口, 定义了一个compare抽象方法

compare方法可以对两个元素进行比较

    如果方法返回一个小于0的数,表示参数1小于参数2

    如果返回 0 ,表示参数1等于参数2

    如果返回一个大于0的数, 表示参数1大于参数2

演示

8.注意事项

TreeSet集合的存储原理限定了必须要对存入的元素进行比较

要么存入的元素自身实现Comparable接口, 要么提供外部的实现了Comparator接口的比较器, 否则程序运行就会报错


注意点:创建一个TreeSet集合,到底使用哪个比较器?Comparable?Comparator?

无参构造:new TreeSet();-->使用默认的比较器:Comparable

有参构造:new TreeSet(Comparator)-->使用自定义的比较器:Comparator

9.测试题

需求: 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台

演示

10.LinkedHashSet集合

回忆:HashSet存储特点?1、无序。2、去重

HashSet存储数据,记录存储的顺序。

Set集合的另一个实现类:LinkedHashSet

存储原理同HashSet相同,但是外层套了一个链表结构。用于记录存储的顺序。

七. 超级for

1.定义

    Iterator的简写形式

    简化数组和Collection集合的遍历

2.格式

3.演示

4.三种迭代方式的删除

    普通for循环,可以删除,但是需要角标

    迭代器,可以删除,但是必须使用迭代器自身的remove方法,否则会出现并发修改异常

    超级for循环不能删除


八. Collections工具类的使用

1.定义

    一个用于操作Collection集合工具类

2.常用方法

    sort(List list) 根据元素的自然顺序排序

    swap(List list , int i , int j) 交换集合中两个角标位上的值

    reverse(List list ) 反转集合中的元素的顺序

    replaceAll(List list, T oldVal, T newVal) 替换

3.演示


总结

1.Set集合:特点,去重,无序。

2.HashSet:

    去重效率高, 尤其是在大数据量下,散列存储。不讲究存储顺序。

    调用元素的hashCode和equals方法来比较是否相同

3.TreeSet:

    去重, 元素有序(对存入的元素进行排序)

    要求存入的元素必须具备比较的能力或者提供第三方的比较器

    元素具备比较的能力 : 元素实现comperable接口, 重写comparTo方法

    第三方比较器: 定义类,实现Compartor接口, 从写  compare方法

4.LinkedHashSet

    即有序(集合有序), 又能去重

    效率不高

5.超级for

    迭代器的简写形式

    优点: 格式简单

    缺点: 无法进行删除操作

6.Collections

    一个用来操作List集合的工具类

你可能感兴趣的:(Set集合)