jdk源码分析(六)——HashSet
我们在jdk源码分析(四)——ArrayList和jdk源码分析(五)——HashMap中分别分析了List和Map两种数据结构,在Java的集合框架中,还有另一类成员,就是Set,今天我们就来看看常用的
HashSet
。
一.类定义
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
可以看到,和HashMap
类似,HashSet
也是继承了一个抽象类,并实现了一个基础的接口Set
。
Set
接口中的主要方法如下:
核心的方法都是一些对集合的操作,例如添加元素,判断元素是否存在,遍历,删除等。
二.存储结构
HashSet
主要是使用HashMap
来实现元素的存储的:
// 存储集合元素
private transient HashMap<E,Object> map;
// 常量,表示某个集合元素存在,在map中作为value
private static final Object PRESENT = new Object();
因此主要操作都是围绕着这个map
进行的,自然不可避免的要使用到我们上一篇中讲到的HashMap
了。map
的value
是Object
类型的常量。
三.常用方法
1.构造方法
先来看看无参构造方法:
public HashSet() {
map = new HashMap<E,Object>();
}
代码很简单,只有一行,完成对map
的实例化,以备使用。
除了无参构造方法外,还可以基于已有的集合类来初始化HashMap
:
public HashSet(Collection<? extends E> c) {
map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
首先调用了HashMap
的构造方法,并指定map
的初始容量。初始容量的计算方法如下:
(1)将集合中的元素个数除以0.75,向上取整
(2)取(1)中结果与16中的较大者
通过HashMap
的源码分析,我们已经知道,HashMap
的默认装载因子是0.75(也就是说,默认只装载75%左右的位置),而HashSet
底层使用HashMap
来存储,因此需要根据这个装载因子算出需要的散列表大小。而HashMap
的默认大小是16,因此这里的初始化大小最小是16。
2.add方法
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
逻辑实现也很简单,就是调用HashMap
的put
方法,将需要存储的集合元素作为key,将常量PRESENT
作为value。put
方法的返回值是map中与此key关联的value值,某个元素第一次存入时返回null,如果key已经存在,则返回此key对应的value。
需要注意的是,HashMap
是允许key覆盖的,而集合Set的特性决定了,Set中同一个元素只能存在一次,因此,如果集合中已经存在该元素了,那么map的返回值为非null,从而add
方法返回false。
3.contains方法
public boolean contains(Object o) {
return map.containsKey(o);
}
该方法也比较简单,直接调用HashMap
的containsKey
方法来判断元素是否存在。
HashSet
的实现比较容易理解,我们就不再啰嗦了,轻松加愉快。期待与大家一起学习后面的jdk源码。
本文已迁移至我的博客:http://ipenge.com/54585.html