Java——集合(Collection子接口——Set接口)

集合(Collection子接口——Set接口)

Set 接口概述

Set接口存储无序的,不可重复的数据(类似高中所学的集合)。
Set接口是Collection的子接口,set接口没有提供额外的方法。
Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set 集合中,则添加操作失败。
Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals() 方法。
Set接口的实现类 HashSet,LinkedHashSet 和TreeSet 。

以HashSet为例:
无序性:不等于随机性。(存放位置无序性)存储的数据在底层数组中并非按照数组的索引的顺序去添加的,而是根据数据的哈希值决定的。

不可重复性:保证添加的元素按照equals()判断时,不能返回true。即相同的元素只能添加一个。

euqals()和 = = 的区别

添加元素的过程:以HashSet为例:
在这里插入图片描述

我们想HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值通过某种算法计算出HashSet底层数组中的存放位置(索引位置),然后在判断此位置上是否已经有元素:

  1. 如果此位置上没有其他元素,则元素 a添加成功。
  2. 如果此位置上有其他元素 b(或者是有以链表形式存在的多个元素),则比较元素a与元素b的哈希值 :
    如果哈希值不同,则元素a 添加成功。
    如果哈希值相同,则需要调用元素a所在类的equals()方法:
    equals()方法返回true,则元素a添加失败。
    equals()方法返回false,则元素a添加成功。

通过图片和之前所说的添加元素的方法,能看出来我们HsahSet在底层是一个数组加链表的方法存储数据。

jdk7:将元素a放到数组中,指向原来的元素。
jdk8:原来的元素在数组中,指向元素a。
总结: 七上八下

HashSet

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

HashSet 具有以下特点:

  1. 不能保证元素的排列顺序
  2. HashSet 不是线程安全的
  3. 集合元素可以是 null

HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。
对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码(哈希值)”。

HashSet扩容问题:
底层也是数组,初始容量为16,当如果使用率超过0.75,(16*0.75=12)就会扩大容量为原来的2倍。(16扩容为32,依次为64,128…等)。

问题:
以Eclipse/IDEA为例,在自定义类中可以调用工具自动重写equals和hashCode。为什么用Eclipse/IDEA复写hashCode方法,有31这个数字?

  1. 选择系数的时候要选择尽量大的系数。因为如果计算出来的hash地址越大,所谓的“冲突”就越少,查找起来效率也会提高。(减少冲突)
  2. 并且31只占用5bits,相乘造成数据溢出的概率较小。
  3. 31可以 由i*31== (i<<5)-1来表示,现在很多虚拟机里面都有做相关优化。(提高算法效率)
  4. 31是一个素数,素数作用就是如果我用一个数字来乘以这个素数,那么最终出来的结果只能被素数本身和被乘数还有1来整除!(减少冲突)

LinkedHashSet

LinkedHashSet 是 HashSet 的子类。
LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的。但是是无序的。(存放位置无序)
LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全
部元素时有很好的性能。
LinkedHashSet 不允许集合元素重复。

在这里插入图片描述

TreeSet

TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。也就是说TreeSet可以按照添加对象的指定属性,进行排序。所以在向TreeSet中添加数据时,要求是相同类的对象,因为只有相同类的对象才能比较。
TreeSet底层使用红黑树结构存储数据。所以不能存放相同数据。
TreeSet 两种排序方法:自然排序和定制排序。默认情况下,TreeSet采用自然排序。

自然排序

自然排序:TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序(默认情况)排列
如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现Comparable 接口。
向 TreeSet 中添加元素时,只有第一个元素无须比较compareTo()方法,后面添加的所有元素都会调用compareTo()方法进行比较。

对于 TreeSet 集合而言,它判断两个对象是否相等的唯一标准是:两个对象通过 compareTo(Object obj) 方法比较返回值。不再是equals()方法。
实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过compareTo(Object obj) 方法的返回值来比较大小。
Comparable 的典型实现:
BigDecimal、BigInteger 以及所有的数值型对应的包装类:按它们对应的数值大小进行比较
Character:按字符的 unicode值来进行比较
Boolean:true 对应的包装类实例大于 false 对应的包装类实例
String:按字符串中字符的 unicode 值进行比较
Date、Time:后边的时间、日期比前面的时间、日期大

定制排序

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。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

真真最可爱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值