Collection子接口之二:Set接口

Collection子接口之二:Set接口

Set接口概述

  1. Set接口是Collection的子接口,set接口没有提供额外的方法
  2. Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set 集合中,则添加操作失败
  3. Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals() 方法

##理解Set的无序性和不可重复性(以HashSet为例)

  1. 无序性,不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值来添加
  2. 不可重复性:添加的元素按照equals()方法判断时,不能返回true,即:相同的元素只能添加一个

理解Set添加元素的过程(以HashSet为例)

  1. 当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值,通过某种散列数决定该对象在 HashSet 底层数组中的存储位置。(这个散列函数会与底层数组的长度相计算得到在数组中的下标,并且这种散列函数计算还尽可能保证能均匀存储元素,越是散列分布,该散列函数设计的越好)

  2. 如果两个元素的hashCode()值相等,会再继续调用equals方法,如果equals方法结果为true,添加失败;如果为false,那么会保存该元素,但是该数组的置已经有元素了,那么会通过链表的方式继续链接。

  3. 如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。

  4. 示意图如下:

在这里插入图片描述

Set接口实现类之一:HashSet

  1. HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。
  2. HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取、查找、删除性能。
  3. HashSet 具有以下特点:
    • 不能保证元素的排列顺序
    • HashSet 不是线程安全的
    • 集合元素可以是 null
  4. HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。
  5. 对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode(Objecobj)方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”。

Set接口实现类之二:LinkedHashSet

  1. LinkedHashSet 是 HashSet 的子类

  2. LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的

  3. LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能

  4. LinkedHashSet 不允许集合元素重复。

  5. 如下图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C4PDOUKg-1652193020962)(C:\Users\Think\AppData\Roaming\Typora\typora-user-images\image-20220509212513896.png)]

在添加数据的同时,每个数据还维护了两个引用(底层是一个双向链表),记录该数据的前一个数据和后一个数据,这样做的好处对于频繁的遍历操作效率比较高

Set接口实现类之三:TreeSet

  1. TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。

  2. TreeSet底层使用红黑树结构存储数据

  3. TreeSet 两种排序方法:自然排序定制排序。默认情况下,TreeSet 采用自然排序。

    • 自然排序
      1. TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序(默认情况)排列
      2. 如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable 接口。
      3. 实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过compareTo(Object obj) 方法的返回值来比较大小。
    • 定制排序
      1. 要实现定制排序,需要将实现Comparator接口的实例作为形参传递给TreeSet的构造器。
      2. 此时,仍然只能向TreeSet中添加类型相同的对象。否则发生ClassCastException异常
      3. 使用定制排序判断两个元素相等的标准是:通过Comparator比较两个元素返回了0。
  4. 向TreeSet中添加的数据,要求是相同对象

  5. 向 TreeSet 中添加元素时,只有第一个元素无须比较compareTo()方法,后面添加的所有元素都会调用compareTo()方法进行比较。

  6. 因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同一个类的对象。

  7. 对于 TreeSet 集合而言,它判断两个对象是否相等的唯一标准是:两个对象通过 compareTo(Object obj) 方法比较返回值

  8. 当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 方法时,应保证该方法与 compareTo(Object obj) 方法有一致的结果:如果两个对象通过

    equals() 方法比较返回 true,则通过 compareTo(Object obj) 方法比较应返回 0。否则,让人难以理解。

hashSet经典面试:

HashSet set = new HashSet();
Person p1 = new Person(1001,"AA");
Person p2 = new Person(1002,"BB");
set.add(p1);
set.add(p2);
p1.name = "CC";
set.remove(p1);
System.out.println(set);
set.add(new Person(1001,"CC"));
System.out.println(set);
set.add(new Person(1001,"AA"));
System.out.println(set);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值