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【笔记】的更多相关文章

  1. Java——HashSet和TreeSet的区别

    HashSetHashSet有以下特点 不能保证元素的排列顺序,顺序有可能发生变化 不是同步的 集合元素可以是null,但只能放入一个null当向HashSet集合中存入一个元素时,HashSe ...

  2. Java开发笔记(六十五)集合:HashSet和TreeSet

    对于相同类型的一组数据,虽然Java已经提供了数组加以表达,但是数组的结构实在太简单了,第一它无法直接添加新元素,第二它只能按照线性排列,故而数组用于基本的操作倒还凑合,若要用于复杂的处理就无法胜任了 ...

  3. java集合系列——Set之HashSet和TreeSet介绍(十)

    一.Set的简介 Set是一个不包含重复元素的 collection.更确切地讲,set 不包含满足 e1.equals(e2) 的元素.对 e1 和 e2,并且最多包含一个为 null 的元素. S ...

  4. Java集合详解7:HashSet,TreeSet与LinkedHashSet

    今天我们来探索一下HashSet,TreeSet与LinkedHashSet的基本原理与源码实现,由于这三个set都是基于之前文章的三个map进行实现的,所以推荐大家先看一下前面有关map的文章,结合 ...

  5. 【java提高】---HashSet 与TreeSet和LinkedHashSet的区别

    HashSet 与TreeSet和LinkedHashSet的区别 今天项目开发,需要通过两个条件去查询数据库数据,同时只要满足一个条件就可以取出这个对象.所以通过取出的数据肯定会有重复,所以要去掉重 ...

  6. Java 容器 & 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较

    Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 上一篇总结了下ArrayList .LinkedList和Vector比较,今天泥瓦匠总结下Hash ...

  7. Java容器深入浅出之HashSet、TreeSet和EnumSet

    Java集合中的Set接口,定义的是一类无顺序的.不可重复的对象集合.如果尝试添加相同的元素,add()方法会返回false,同时添加失败.Set接口包括3个主要的实现类:HashSet.TreeSe ...

  8. 30、Java中Set集合之HashSet、TreeSet和EnumSet

    Set集合是Collection的子集,Set集合与Collection基本相同,没有提供任何额外的方法,只是Set不允许包含重复的元素. Set集合3个实现类:HashSet.TreeSet.Enu ...

  9. Java集合详解7:一文搞清楚HashSet,TreeSet与LinkedHashSet的异同

    <Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...

随机推荐

  1. redis--hash的实现

    Redis数据结构---字典,哈希表,dict 或java中的map,数据使用key -> value的形式存储,整个redis数据库就是基于字典实现,api见hash REDIS的hash实现 ...

  2. 干掉 Postman?测试接口直接生成API文档,这个工具贼好用

    大家好,我是小富~ 前几天粉丝群有小伙伴问,有啥好用的API文档工具推荐,无意间发现了一款工具,这里马不停蹄的来给大家分享一下. ShowDoc一个非常适合团队的在线API文档工具,也支持用docke ...

  3. 【笔记】Python编程 从入门到实践 第二版(基础部分)

    1 字符串相关函数 .title() # 将字符串每个单词的首字母大写 .upper() #不改变字符串变量的值 .lower() #不改变字符串变量的值 f"{var} ,字符串" ...

  4. NOIP 模拟赛 day5 T2 水 故事题解

    题目描述 有一块矩形土地被划分成 \(\small n×m\) 个正方形小块.这些小块高低不平,每一小块都有自己的高度.水流可以由任意一块地流向周围四个方向的四块地中,但是不能直接流入对角相连的小块中 ...

  5. C#版Nebula客户端编译

    一.需求背景 从Nebula的Github上可以发现,Nebula为以下语言提供了客户端SDK: nebula-cpp nebula-java nebula-go nebula-python nebu ...

  6. java001-java基础

    基础数据类型 int--->Integer long--->Long float--->Float double--->Double boolean--->Boolean ...

  7. CentOS更换网易yum源

    最新内容和地址参见http://mirrors.163.com/.help/centos.html 1 首先备份/etc/yum.repos.d/CentOS-Base.repo mv /etc/yu ...

  8. Linux安装Tomcat-Nginx-FastDFS-Redis-Solr-集群——【第九集-补充-热部署项目到tomcat中,但是数据库配置文件错误,中途停止部署,导致执行shutdow.sh报错异常: Could not contact localhost:8005. Tomcat may not be running error while shutting down】

    1,经过千辛万苦的尝试和百度,终于一个博客:http://stackmirror.caup.cn/page/skxugjqj0ldc关于catalina.sh文件的执行引起了我的注意: 2,我执行ca ...

  9. Junit测试用例配置Log4j

    用Junit测试非常方便,但有时我们想要看日志来方便排除,使用spring+log4j时,用Junit测试看日志很多人都不太会,即如何将Junit与log4j进行整合. 我也是研究了半天,才终于找到了 ...

  10. 痞子衡嵌入式:i.MXRT1010, 1170型号上不一样的SNVS GPR寄存器读写控制设计

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1010, 1170型号上不一样的SNVS GPR寄存器读写控制设计. 痞子衡之前两篇文章 <在SBL项目实战中妙用i ...