Java HashSet和TreeSet【笔记】
Java HashSet和TreeSet【笔记】
PS:HashSet、TreeSet 两个类是在 Map 的基础上组装起来的类
HashSet
类注释
1.底层实现基于 HashMap,所以迭代时不能保证按照插入顺序,或者其它顺序进行迭代
2.add、remove、contanins、size 等方法的耗时性能,是不会随着数据量的增加而增加的,这个主要跟 HashMap 底层的数组数据结构有关,不管数据量多大,不考虑 hash 冲突的情况下,时间复杂度都是 O (1)
3.线程不安全的,如果需要安全请自行加锁,或者使用 Collections.synchronizedSet
4.迭代过程中,如果数据结构被改变,会快速失败的,会抛出 ConcurrentModificationException 异常
HashSet结构
HashSet使用的就是组合 HashMap,组合就是把 HashMap 当作自己的一个局部变量
在 Java 中,要想基于基础类进行创新实现的话,有两种办法:
第一种是继承基础类,覆写基础类的方法,比如说继承 HashMap , 覆写其 add 的方法
第二种是组合基础类,通过调用基础类的方法,来复用基础类的能力
其优点如下:
1.继承表示父子类是同一个事物,而 Set 和 Map 本来就是想表达两种事物,所以继承不妥,而且 Java 语法限制,子类只能继承一个父类,后续难以扩展
2.组合更加灵活,可以任意的组合现有的基础类,并且可以在基础类方法的基础上进行扩展、编排等,而且方法命名可以任意命名,无需和基础类的方法名称保持一致
HashSet 初始化
HashSet 的初始化直接 new HashMap 即可,有意思的是,在有原始数据进行初始化的情况下,会对 HashMap 的初始容量进行计算(取括号中两个数的最大值,Math.max((int) (c.size()/.75f) + 1, 16))
源码:
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
可以看出两方面的事情
第一,和 16 比较大小的意思是说,如果给定 HashMap 初始容量小于 16 ,就按照 HashMap 默认的 16 初始化好了,如果大于 16,就按照给定值初始化
第二,HashMap 扩容的伐值的计算公式是:Map 的容量 * 0.75f,一旦达到阀值就会扩容,此处用 (int) (c.size ()/.75f) + 1 来表示初始化的值,这样使我们期望的大小值正好比扩容的阀值还大 1,就不会扩容,符合 HashMap 扩容的公式
HashSet 其他方法
其他方法就是对 Map 的 api 进行了一些包装,如下的 add 方法实现,直接使用 HashMap 的 put 方法,进行一些简单的逻辑判断
代码:
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
从 add 方法中,我们就可以看到组合的好处,方法的入参、名称、返回值都可以自定义,如果是继承的话就不能自定义了
HashSet值得参考的地方
1.对组合和继承的分析和把握
2.对复杂逻辑的包装,要让放出去的接口尽量简单好用
3.尽量多对组合的 api 多些了解,这样在组合其他 api 时,才能更好的使用 api
TreeSet
TreeSet基本结构
TreeSet 的结构和 HashSet 相似,底层组合的是 TreeMap,所以其继承了 TreeMap key 能够排序的功能,在迭代的时候,也可以按照 key 的排序顺序进行迭代
TreeSet 组合 TreeMap 实现的思路
TreeSet 组合 TreeMap 实现的思路有两种
第一种,TreeSet 直接使用 TreeMap 的某些功能,自己包装成新的 api(add方法),适合用于简单的场景
add方法源码:
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
第二种,TreeSet 定义自己想要的 api,自己定义接口规范,让 TreeMap 去实现(NavigableSet 接口),也就是说,TreeSet 把接口定义出来后,让 TreeMap 去实现内部逻辑,TreeSet 负责接口定义,TreeMap 负责具体实现,适合用于复杂的场景,这种思想比较重要,很多都是这种复用思想
NavigableSet 接口源码:
public interface NavigableSet<E> extends SortedSet<E> {
Iterator<E> iterator();
E lower(E e);
}
public Iterator<E> iterator() {
return m.navigableKeySet().iterator();
}
比较重要的就是HashSet 小结以及TreeSet 两种复用思路

Java HashSet和TreeSet【笔记】的更多相关文章
- Java——HashSet和TreeSet的区别
HashSetHashSet有以下特点 不能保证元素的排列顺序,顺序有可能发生变化 不是同步的 集合元素可以是null,但只能放入一个null当向HashSet集合中存入一个元素时,HashSe ...
- Java开发笔记(六十五)集合:HashSet和TreeSet
对于相同类型的一组数据,虽然Java已经提供了数组加以表达,但是数组的结构实在太简单了,第一它无法直接添加新元素,第二它只能按照线性排列,故而数组用于基本的操作倒还凑合,若要用于复杂的处理就无法胜任了 ...
- java集合系列——Set之HashSet和TreeSet介绍(十)
一.Set的简介 Set是一个不包含重复元素的 collection.更确切地讲,set 不包含满足 e1.equals(e2) 的元素.对 e1 和 e2,并且最多包含一个为 null 的元素. S ...
- Java集合详解7:HashSet,TreeSet与LinkedHashSet
今天我们来探索一下HashSet,TreeSet与LinkedHashSet的基本原理与源码实现,由于这三个set都是基于之前文章的三个map进行实现的,所以推荐大家先看一下前面有关map的文章,结合 ...
- 【java提高】---HashSet 与TreeSet和LinkedHashSet的区别
HashSet 与TreeSet和LinkedHashSet的区别 今天项目开发,需要通过两个条件去查询数据库数据,同时只要满足一个条件就可以取出这个对象.所以通过取出的数据肯定会有重复,所以要去掉重 ...
- Java 容器 & 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 上一篇总结了下ArrayList .LinkedList和Vector比较,今天泥瓦匠总结下Hash ...
- Java容器深入浅出之HashSet、TreeSet和EnumSet
Java集合中的Set接口,定义的是一类无顺序的.不可重复的对象集合.如果尝试添加相同的元素,add()方法会返回false,同时添加失败.Set接口包括3个主要的实现类:HashSet.TreeSe ...
- 30、Java中Set集合之HashSet、TreeSet和EnumSet
Set集合是Collection的子集,Set集合与Collection基本相同,没有提供任何额外的方法,只是Set不允许包含重复的元素. Set集合3个实现类:HashSet.TreeSet.Enu ...
- Java集合详解7:一文搞清楚HashSet,TreeSet与LinkedHashSet的异同
<Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...
随机推荐
- 学会这些CSS技巧让你写样式更加丝滑
目录 1,前言 1,calc() 2,min() 3,max() 4,clamp() 5,gap 6,writing-mode 1,前言 记录一些很好用的css属性 1,calc() calc()函数 ...
- SpringMVC(9)实现注解式权限验证
对大部分系统来说都需要权限管理来决定不同用户可以看到哪些内容,那么如何在Spring MVC中实现权限验证呢?当然我们可以继续使用servlet中的过滤器Filter来实现.但借助于Spring MV ...
- Java线程池中的核心线程是如何被重复利用的?
真的!讲得太清楚了!https://blog.csdn.net/MingHuang2017/article/details/79571529 真的是解惑了 本文所说的"核心线程". ...
- pdfkit html转pdf
pdfkit的通用option选项 参考:https://cloud.tencent.com/developer/ask/202116https://www.cnblogs.com/taceywong ...
- 18 shell 重定向以及文件描述符
1.对重定向的理解 2.硬件设备和文件描述符 文件描述符到底是什么 3.Linux Shell 输出重定向 4.Linux Shell 输入重定向 5.结合Linux文件描述符谈重定向 6.Shell ...
- 使用Nginx和uwsgi部署Flask项目
前言 之前用Flask框架开发了一个Python的Web项目,使用Nginx和uWSGI部署起来感觉挺麻烦,过程中还因为对Flask框架的不熟悉,花了好长时间才把应用完全部署起来.下面分享部署成功 ...
- Spark编程基础_RDD编程
RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变.可分区.里面的元素可并行计算的集合.RDD具有数据流模型的特 ...
- final修饰符(6)-final类
final修饰的类不可以有子类,例如:java.lang.Math类就是一个final类,它不可以有子类 子类继承父类,可以访问父类的内部数据,可以重写父类的方法来改变父类方法的实现细节,可能导致不安 ...
- ESP8266 NodeMCU小白手把手入门(实操篇)以土壤湿度和DHT传感器为例讲解读取传感器的值
物联网使得现实世界中的实体和数字世界比以往任何时候都更紧密地联系在一起.NodeMCU作为其中的一个重要设备,作用之一就是与传感器相连以实现万物互联通讯.这篇关于NodeMCU的实操篇以土壤湿度传感器 ...
- K8s基本概念资料
https://www.cnblogs.com/menkeyi/p/7134460.html