查看原文
其他

【194期】HashSet 是无序的吗?为什么输出的结果有序?

素文宅博客 Java精选 2022-08-09

点击上方“Java精选”,选择“设为星标”

别问别人为什么,多问自己凭什么!

下方有惊喜,留言必回,有问必答!

每天 08:15 更新文章,每天进步一点点...

什么是集合?
集合简称集,是数学中一个基本的概念,主要体现两方面的特征:
1)一个集合中,任何两个元素都可以认为是不相同的,即为每个元素只能出现一次。
2)一个集合中,每个元素的地位都是相同的,元素之间是无序的。
什么是Set集合?
Set集合是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。Set接口主要实现了两个实现类:HashSet类按照哈希算法来存取集合中的对象,存取速度比较快;TreeSet类实现了SortedSet接口,能够对集合中的对象进行排序。
Set集合不允许包含相同的元素,如果试图把两个相同元素加入同一个Set集合中,则添加操作失败,add()方法返回false,且新元素不会被加入。
Set接口是没有所谓的有序和无序的概念,TreeSet是有序的,但此有序是说读取数据的顺序和插入的数据的顺序一致。
HashSet无序吗?
HashSet中无序是指读取数据的顺序不一定和插入数据的顺序一样。但是HashSet真实的情况是有序的,只不过它是通过内部HashCode方法计算hash值后自动进行了排序,所以读取的是经过内部排序后的数据,且此数据每次结果都是一样的顺序。
简单说一说哈希表
一个元素为链表的数组,综合了数组与链表的优点。
HashSet具有以下特点:
1)不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也可能发生变化;
2)HashSet不是同步的;
3)集合元素值可以是null。
同样的,HashMap和HashSet是一样的,HashMap是根据key的hash值进行了排序。
HashSet底层是基于HashMap实现的,HashSet存放的数据实际就是HashMap的key,而HashMap的value存放的是一个静态的final对象PERSENT;当调用HashSet无参构造函数的时候,实际只是实例化了HashMap对象。

HashSet源码,无参构造函数如下:

public HashSet() {
//实例化map成员变量
map = new HashMap<>();
}

推荐下自己做的 Spring Cloud 的实战项目:

https://gitee.com/yoodb/jingxuan-springcloud

HashSet集合中,假如自然数或字符串(单字符或多字符)输出是有序还是无序呢?
public class JingXuanApplication {
public static void main(String[] args) throws Exception {
Random ran = new Random();
Set<Integer> set = new HashSet<>();
while(set.size() < 20) {
set.add(ran.nextInt(20)+1);
}
for (Integer integer : set) {
System.out.println(integer);
}
}
}

当按照上述代码插入数据后,发现读取出来的数据如下方输出结果顺序,这是因为正好插入数据的hash值是按照这个顺序排列的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

从上面输出结果,单一自然数输出是有序的。那么当插入一个多位的数值时会出现什么样的变化呢?

public class JingXuanApplication {
public static void main(String[] args) throws Exception {
Random ran = new Random();
Set<Integer> set = new HashSet<>();
while(set.size() < 20) {
set.add(ran.nextInt(2000)+1);
}
for (Integer integer : set) {
System.out.println(integer);
}
}
}
输出结果则每次都不会相同,此次输出结果如下:
1280
1345
419
1861
1317
135
1704
1770
171
1835
588
1298
498
178
597
408
954
1114
1725
1790
总结
Set的实现类HashSet底层是基于HashMap实现的,HashSet存储的元素对应hashMap的key,因为HashMap不能存储重复的Key,所以HashSet不能存放重复元素;由于HashMap的key是基于hashCode存储对象的,所以HashSet中存放的对象也是无序的;HashSet也没有提供get方法,可以通过Iterator迭代器获取数据。
HashSet中元素是按照它们的HashCode值排序存储的,hash算法混淆程度低,在[0, 2^32-1]范围内经过HashMap.hash()之后还是得到之前的结果。
对于单个字符而言,这些HashCode是按照ASCII码,因此,当按顺序添加自然数或者26个英文字符时,会产生一种HashSet也可以有序输出“错觉”的假象。
公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!
------ THE END ------

精品资料,超赞福利!


3000+ 道面试题在线刷,最新、最全 Java 面试题!

期往精选  点击标题可跳转

【186期】面试官问:OAuth2 vs JWT,到底怎么选择?

【187期】Java 中的 BigDecimal 运算,如何解决精度丢失问题?

【188期】面试官问:如何防止你的 jar 包被反编译?

【189期】利用 Fastjson 注入 Spring MVC 内存马,太秀了~!

【190期】对 volatile 的理解—从 JMM 以及单例模式剖析

【191期】Redis 延时任务详细解读,高手养成篇

【192期】面试官问:说说 Tomcat 组成与工作原理?

【193期】为什么要使用注册中心?是 Eureka 还是 Nacos?

技术交流群!

最近有很多人问,有没有读者&异性交流群,你懂的!想知道如何加入。加入方式很简单,有兴趣的同学,只需要点击下方卡片,回复“加群”,即可免费加入交流群!

文章有帮助的话,在看,转发吧!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存