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面试指南>仓库,更多精彩内容请到我的仓库里查 ...
随机推荐
- Java:java获取Linux下的路径
指定Linux的路径 //Linux系统路径 StringBuilder sb = new StringBuilder(File.separator); String Url = sb.append( ...
- mybatis框架的第二天
一.mybatis的基础crud的操作 先在接口中,写对应的方法名称,返回类型,访问符. 之后在映射配置文件中,写具体的实现 二.mybati中crud的细节 1.模糊查询 这是接口中 这是xml中 ...
- nmon打开nmon文件出现 运行时错误13类型不匹配问题解决
根据nmon工具安装及nmon analyser的使用 - 空谷幽兰LDD - 博客园 (cnblogs.com)文中,用nmon_analyse去打开监控到的nmon文件,出几个报错. 1 用WPS ...
- Python装饰器、迭代器&生成器、re正则表达式、字符串格式化
Python装饰器.迭代器&生成器.re正则表达式.字符串格式化 本章内容: 装饰器 迭代器 & 生成器 re 正则表达式 字符串格式化 装饰器 装饰器是一个很著名的设计模式,经常被用 ...
- 《快来为你的 .NET 应用加个监控吧!》更新版本啦
目录 导读 三种方式处理监控数据 主动推送 ASP.NET Core 自定义URL .NET diagnostics 自定义监控指标 导读 CZGL.ProcessMetrics 是一个 Metric ...
- python 16篇 多线程和多进程
1.概念 线程.进程 进程 一个程序,它是一组资源的集合 一个进程里面默认是有一个线程的,主线程 多进程是可以利用多核cpu的线程 最小的执行单位 线程和线程之间是互相独立的 主线程等待子线程执行结束 ...
- 在HTML中使用JavaScript(浏览器对js的加载机制分析)
前言: 向HTML页面中插入JavaScrip的主要方法,就是使用<script>标签.主要探讨<script>标签的在HTML页面的渲染机制.对应的业务场景:从js的加载机制 ...
- Python 创建一个Django项目
1 环境搭建及创建 1) 安装Django 方法一:pip install django 方法二:Pycharm File--settings--Project--Python Interpreter ...
- PHP获取当日或本月时间戳范围
在mysql数据库中使用int类型保存时间戳时,一般在程序中可能会用到统计当日,当月的一些数据.那么可以用如下的方式限定时间范围: //当日销售 $today_start = strtotime( ...
- tomcat日志详解
1 tomcat 日志详解 1.1 tomcat 日志配置文件 tomcat 对应日志的配置文件:tomcat目录下的/conf/logging.properties. tomcat 的日志等级有:日 ...