原创

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

什么是集合?
集合简称集,是数学中一个基本的概念,主要体现两方面的特征:
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对象。

推荐下自己做的 Spring Cloud 的实战项目:https://gitee.com/yoodb/jingxuan-springcloud

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

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

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精选”(w_z90110),专注Java技术干货分享!让你从此路人变大神!回复关键词领取资料:如Mysql、Hadoop、Dubbo、Spring Boot等,免费领取视频教程、资料文档和项目源码。微信搜索小程序“Java精选面试题”,内涵3000+道Java面试题!

涵盖:互联网那些事、算法与数据结构、SpringMVC、Spring boot、Spring Cloud、ElasticSearch、Linux、Mysql、Oracle等

评论

分享:

支付宝

微信