首先明确一点:HashSet的底层就是HashMap
HashSet与HashMap的不同点:
HashMap存储的是键值对(也就是key-value),即在调用HashMap的put方法时传入的两个值,而HashSet其实也是存储的键值对,但是键值对的value是一个默认值(PRESENT,一个Object的对象)
HashSet的方法也只能将key取出,不能取出value,而HashMap就有方法能将value也取出
既然说HashSet的底层是HashMap,那来看看源码:
来看看HashSet的add方法源码:
map是什么?
可以看到map是HashSet这个类的属性,这个属性是HashMap的一个对象,这样就可以通过这个map对象来调用HashMap的方法
果然:
用map调用了HashMap的put方法,这就是为什么说HashSet的底层使用的是HashMap,很多方法都是直接调用HashMap的方法,比如remove
接着讲add方法
put方法传入了两个值,一个是你自己输入的(e),一个是默认值,也就是刚才说的PRESENT
HashSet要添加数据调用的是add方法,而HashMap添加数据调用的是put方法,实际add方法也是调用的HashMap的put方法,这一点可以从上面源码看出;
我们再来通过put方法分析HashMap的内部结构(内部类,内部接口)
进入put方法
put方法有调用的putVal方法
putVal方法里面又调用的hash方法,hash方法是通过传入的key值来计算hash值,来确定键值对在table表中的位置,table表就是一个数组,这个数组存放的就是键值对(HashMap$Node类型),为什么table数组存放的是HashMap$Node类型的数据?马上就有解释
进入putVal方法:
这一堆代码就是添加数据的底层源码了,我只分析内部结构
可以看到这里有个table,这就是刚才说的table数组,键值对都存储在这个数组里面
看一下table的定义:是一个Node类型的数组,那Node又是什么呢?
Node就是HashMap的内部类
这里有个newNode方法:
newNode方法就是调用Node这个内部类的构造器创建了一个Node对象,并返回,再将这个对象放入table数组里
这里就是为什么table数组的类型是HashMap$Node类型的原因了,还记不记得,new一个内部类,这个新new出来的对象其实是一个新匿名内部类的对象,这个匿名内部类的名字系统分配的规则就是外部类名+ $ + 内部类名,原理相当于 HashMap(外部类)$Node(内部类) extends Node(内部类) ,所以用Node是新类的父类,用Node去接收是没问题的