HashSet与HashMap源代码深度剖析
HashSet源码分析:
先来看一下它的构造方法:

呃~~居然它的底层是用HashMap来实现的,颠覆三观,那它究竟是如何来用的呢?继续来往下跟:

对于HashSet而言是没有key->value的结构的,那它是怎么跟HashMap关联到一块的呢?接着得查看add方法了:

也就是将我们往HashSet添加的元素是被用作HashMap的key,而HashMap的Value是一个常量,看一下它长啥样:

而这个字段也说明了,它是一个"Dummy value",也就是假的值,因为对于HashSet来说,只需要用到HashMap的key就行了,对于value不关心。
接着再来看一下删除元素的实现:

当然都是借助于HashMap来删除喽~

那它的其它方法其上差不多了,既然底层是由HashMap来实现的,那接下来就得探究一下HashMap的底层原理喽。
HashMap源码分析:

先来查看一下空的构造方法:
然后一句句代码来分析一下:

这有什么意义呢?这是因为通过散列来决定当前的元素达到总集合的75%时,则认为集合就快满了,所以就要考虑给集合进行扩容了,

这是干嘛滴,先不管,其中又用到了一个新的常量:


目前貌似一脸懵逼,不晓得这些变化是干嘛的,先放着,继续往下分析:

所以整个构造函数是初始化了一个长度为16的Entry类型的数组,那这个Entry又是啥呢?

接着再来分析放里面放元素的方法:

呃,貌似很复杂,但要想搞清楚原理必须得硬着头皮去读它,所以一句句来:

这个不太重要,往下继续:


注意:这个计算出来的并不是真正要添加的位置,真正要添加元素的位置在下一句,如下:


继续回到主流程:


那是如何添加的呢?继续查看该函数的实现,在查看之前先记住最后一个参数i,这是计算出来要存放的元素位置:


注意构造Entry的最后一个参数e:

也就是说将之前的元素做为新构建的Entry的下一个元素了,什么意思,下面用图来表示一下其添加的过程:

目前数组第一个元素已经有一个Entry1对象了,接着再put的时候散列位置时又散列到第一个元素了,此时添加时就会是:

这时就会将以前的那个元素作为新加入的Entry的next元素,因为Entry维护了一个next的引用。
总结:
- HashSet底层是使用HashMap实现的。当使用add方法将对像添加到Set当中时,实际上是将该对象作为底层所维护的Map对象的key,而value则都是同一个Object对象(该对象我们用不上)。
- HashMap底层维护一个数组,我们向HashMap中所放置的对象实际上是存储在该数组当中。
- 当向HashMap中put一对键值时,它会根据key的hashcode值计算出一个位置,该位置就是此对象准备往数组中存放的位置。
- 如果该位置没有对象存在,就将此对象直接放进数组当中;如果该位置已经有对象存在了,则顺着此存在的对象的链开始寻找(Entry类有一个Entry类型的next成员变量,指向了该对象的下一个对象),如果此链上有对象的话,再去使用equals方法进行比较,如果对此链上某个对象的equals方法比较为false,则将该对象放到数组当中,然后将数组中该位置放到数组当中,然后将数组中该位置以前存在的那个对象连接到此对象的后面。
HashSet与HashMap源代码深度剖析的更多相关文章
- Java HashSet和HashMap源码剖析
转自: Java HashSet和HashMap源码剖析 总体介绍 之所以把HashSet和HashMap放在一起讲解,是因为二者在Java里有着相同的实现,前者仅仅是对后者做了一层包装,也就是说Ha ...
- HashMap源代码深入剖析
..
- HashMap源码深度剖析,手把手带你分析每一行代码,包会!!!
HashMap源码深度剖析,手把手带你分析每一行代码! 在前面的两篇文章哈希表的原理和200行代码带你写自己的HashMap(如果你阅读这篇文章感觉有点困难,可以先阅读这两篇文章)当中我们仔细谈到了哈 ...
- 深度剖析HashMap的数据存储实现原理(看完必懂篇)
深度剖析HashMap的数据存储实现原理(看完必懂篇) 具体的原理分析可以参考一下两篇文章,有透彻的分析! 参考资料: 1. https://www.jianshu.com/p/17177c12f84 ...
- 【Java集合源代码剖析】HashMap源代码剖析
转载请注明出处:http://blog.csdn.net/ns_code/article/details/36034955 您好,我正在參加CSDN博文大赛,假设您喜欢我的文章.希望您能帮我投一票.谢 ...
- Java_深度剖析ConcurrentHashMap
本文基于Java 7的源码做剖析. ConcurrentHashMap的目的 多线程环境下,使用Hashmap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用Hash ...
- 深度剖析ConcurrentHashMap(转)
概述 还记得大学快毕业的时候要准备找工作了,然后就看各种面试相关的书籍,还记得很多面试书中都说到: HashMap是非线程安全的,HashTable是线程安全的. 那个时候没怎么写Java代码,所以根 ...
- ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程
从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...
- Java反射机制剖析(四)-深度剖析动态代理原理及总结
动态代理类原理(示例代码参见java反射机制剖析(三)) a) 理解上面的动态代理示例流程 a) 理解上面的动态代理示例流程 b) 代理接口实现类源代码剖析 咱们一起来剖析一下代理实现类($Pr ...
随机推荐
- LeetCode.1175-质数排列(Prime Arrangements)
这是小川的第413次更新,第446篇原创 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第264题(顺位题号是1175).返回1到n的排列数,以使质数处于质数索引(索引从1开始).(请 ...
- cnpm 安装vue与vue/cli
cnpm 安装 npm install -g cnpm --registry=https://registry.npm.taobao.org 安装 vue npm install -g npm 安装 ...
- mysql数据库设计字符类型及长度
1.数字类型 小数的我就不聊了,因为有小数点的一般都是用字符串保存.关于整数,有几种可以选TINYINT.SMALLINT.MEDIUMINT.INT和BIGINT,分别占1.2.4.8字节.如果无符 ...
- C++类的对象和类的指针的区别
#include <iostream> #include <string> using namespace std; class Student { public: stati ...
- php 中文unicode 互转
/** * $str 原始中文字符串 * $encoding 原始字符串的编码,默认GBK * $prefix 编码后的前缀,默认"&#" * $postfix 编码后的后 ...
- ThinkPHP composer的安装,及image图像处理类库的加载
以下教程针对windows系统,示例系统使用win7 composer安装 下载composer安装包,点击安装. 出现'composer choose the command-line php' 要 ...
- 深入理解Python中的GIL(全局解释器锁)
深入理解Python中的GIL(全局解释器锁) Python是门古老的语言,要想了解这门语言的多线程和多进程以及协程,以及明白什么时候应该用多线程,什么时候应该使用多进程或协程,我们不得不谈到的一个东 ...
- 超级实用的 Java 工具类
超级实用的 Java 工具类 在Java中,工具类定义了一组公共方法,这篇文章将介绍Java中使用最频繁及最通用的Java工具类.以下工具类.方法按使用流行度排名,参考数据来源于Github上随机选取 ...
- Elastic Search中Query String常见语法
1 搜索所有数据timeout参数:是超时时长定义.代表每个节点上的每个shard执行搜索时最多耗时多久.不会影响响应的正常返回.只会影响返回响应中的数据数量.如:索引a中,有10亿数据.存储在5个s ...
- jsp其实是一个java类
我们打开tomcat的D:\Program_Files\apache-tomcat-8.0.32\work\Catalina\localhost\venus\org\apache\jsp, 当我们访问 ...