java集合-HashSet源码解析
HashSet 无序集合类
- 实现了Set接口
- 内部通过HashMap实现
// HashSet
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
static final long serialVersionUID = -5024744406713321676L;
//重要:HashMap HashSet就是通过HashMap保存数据, HashSet的值就是HashMap的key
private transient HashMap<E,Object> map; // 使用transient修饰不会被序列化
//HashMap 为<key, value>的键值对, 既然HashSet的值就是HashMap的key, 那么HashMap的值呢,当然就是这个PRESENT,HashMap所有的value都是同一个对象
private static final Object PRESENT = new Object();
// 默认构造函数,创建一个HashMap对象
public HashSet() {
map = new HashMap<>();
}
//将一个已知的collection转换为HashSet
public HashSet(Collection<? extends E> c) {
//Collection<? extends E> c 限制了类型上限为E,也就是c只能是E类型或E的子类,防止参数是非Set类型
//如果没有指定HashMap的capacity, 那么默认的就是16
//根据 threshold = capacity * loadFactor, 可以计算出 capacity
//Math.max((int) (c.size()/.75f) + 1, 16) 这个意思就是capacity如果没超过16, 那么就直接使用默认的16
// 容量设置为4/3倍
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
//将已知的collection转换为HashSet的方法
//addAll方法是HashSet的父类AbstractCollection的方法,为了便于阅读,会将代码粘贴在下面
addAll(c);
}
// 带有初始容量和因子的构造函数
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
//addAll方法是HashSet的父类AbstractCollection的方法
public boolean addAll(Collection<? extends E> c) {
boolean modified = false; // 只要添加了元素就返回true
for (E e : c)
//此处的add方法由HashSet重写实现
if (add(e))
modified = true;
return modified;
}
//HashSet的核心方法来了, 没错,就这么简单
public boolean add(E e) {
//应证了上面所说的key为HashSet的值
return map.put(e, PRESENT)==null;
}
//剩下这些方法都是跟Map相关的了,只要熟悉了HashMap, 那就太简单了,就不说了
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
public void clear() {
map.clear();
}
}
补充
泛型
泛型的上限通配符<? extends T>
<? extends T>是 Upper Bound(上限) 的通配符,用来限制元素的类型的上限,比如
List<? extends Fruit> fruits;
表示集合中的元素类型上限为Fruit类型,即只能是Fruit或者Fruit的子类。
泛型的下限通配符<? super T>
<? super E> 是 Lower Bound(下限) 的通配符 ,用来限制元素的类型下限,比如
List<? super Apple> apples;
表示集合中元素类型下限为Apple类型,即只能是Apple或Apple的父类。
参考
- HashSet其实就那么一回事儿之源码浅析 https://www.cnblogs.com/dongying/p/4024519.html
- Java泛型中<? extends E>和<? super E>的区别 https://www.cnblogs.com/xiarongjin/p/8309755.html
java集合-HashSet源码解析的更多相关文章
- Java集合-ArrayList源码解析-JDK1.8
◆ ArrayList简介 ◆ ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了List, RandomAcc ...
- Java集合---LinkedList源码解析
一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据remove()7.数据获取get()8.数据复制clo ...
- java集合类型源码解析之ArrayList
前言 作为一个老码农,不仅要谈架构.谈并发,也不能忘记最基础的语言和数据结构,因此特开辟这个系列的文章,争取每个月写1~2篇关于java基础知识的文章,以温故而知新. 如无特别之处,这个系列文章所使用 ...
- java集合-HashMap源码解析
HashMap 键值对集合 实现原理: HashMap 是基于数组 + 链表实现的. 通过hash值计算 数组索引,将键值对存到该数组中. 如果多个元素hash值相同,通过链表关联,再头部插入新添加的 ...
- java集合类型源码解析之PriorityQueue
本来第二篇想解析一下LinkedList,不过扫了一下源码后,觉得LinkedList的实现比较简单,没有什么意思,于是移步PriorityQueue. PriorityQueue通过数组实现了一个堆 ...
- Java泛型底层源码解析-ArrayList,LinkedList,HashSet和HashMap
声明:以下源代码使用的都是基于JDK1.8_112版本 1. ArrayList源码解析 <1. 集合中存放的依然是对象的引用而不是对象本身,且无法放置原生数据类型,我们需要使用原生数据类型的包 ...
- 【java集合框架源码剖析系列】java源码剖析之HashSet
注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于HashSet的知识. 一HashSet的定义: public class HashSet&l ...
- Java集合框架源码(二)——hashSet
注:本人的源码基于JDK1.8.0,JDK的版本可以在命令行模式下通过java -version命令查看. 在前面的博文(Java集合框架源码(一)——hashMap)中我们详细讲了HashMap的原 ...
- 【java集合框架源码剖析系列】java源码剖析之TreeSet
本博客将从源码的角度带领大家学习TreeSet相关的知识. 一TreeSet类的定义: public class TreeSet<E> extends AbstractSet<E&g ...
随机推荐
- 使用ASP.NET Core支持GraphQL -- 较为原始的方法
GraphQL简介 下面是GraphQL的定义: GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时. GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述 ...
- JavaScript夯实基础系列(五):类
JavaScript中没有类,是通过使用构造函数和原型模式的组合来实现类似其它面向对象编程语言中"类"的功能.ES6引入的关键字class,形式上向其它面向对象编程语言靠拢,其 ...
- 如何利用HTTP缓存来加快你的网站应用
缓存在web环境各个环节都有实现,有CPU缓存.文件缓存.程序的Opcode缓存(APC,eAccelerator).内存缓存(Memcached,Redis).代理服务器(Nginx,Squid). ...
- Angular动态创建组件之Portals
这篇文章主要介绍使用Angular api 和 CDK Portals两种方式实现动态创建组件,另外还会讲一些跟它相关的知识点,如:Angular多级依赖注入.ViewContainerRef,Por ...
- SpringBoot实用小知识之Maven中dependencys和dependencymanagement区别
利用pom管理引用包时,如果是单项目的话就直接在dependencies引用了,若有一个大工程项目里面包含多个子模块,则为了所有项目模块包的版本统一和好管理,则需要用到dependencyManage ...
- Flink从入门到放弃(入门篇1)-Flink是什么
戳更多文章: 1-Flink入门 2-本地环境搭建&构建第一个Flink应用 3-DataSet API 4-DataSteam API 5-集群部署 6-分布式缓存 7-重启策略 8-Fli ...
- [JavaScript] Cookie,localStorage,sessionStorage概述
Cookie Cookie 是一些数据, 存储于你电脑上的文本文件中,当 web 服务器向浏览器发送 web 页面时,在连接关闭后,服务端不会记录用户的信息.Cookie 的作用就是存储 web 页面 ...
- SpringMVC+Spring+Mybatis整合
SpringMVC+Spring+Mybatis整合 导包 配置jdbc.properties.log4j.properties jdbc.driver=com.mysql.jdbc.Driver j ...
- JavaScript实现获取两个排序数组的中位数算法示例
本文实例讲述了JavaScript排序代码实现获取两个排序数组的中位数算法.分享给大家供大家参考,具体如下: 题目 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 . 请找出这两个 ...
- 学习day03
1.结构标记 ***** 做布局 1.<header>元素 <header></header> ==> <div id=&quo ...