追梦 java@IT·互联网程序员

jdk源码分析(六)——HashSet

2017-04-22  本文已影响163人  活成理想中的样子

我们在jdk源码分析(四)——ArrayListjdk源码分析(五)——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了。mapvalueObject类型的常量。

三.常用方法

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;
    }

逻辑实现也很简单,就是调用HashMapput方法,将需要存储的集合元素作为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);
}

该方法也比较简单,直接调用HashMapcontainsKey方法来判断元素是否存在。

HashSet的实现比较容易理解,我们就不再啰嗦了,轻松加愉快。期待与大家一起学习后面的jdk源码。

本文已迁移至我的博客:http://ipenge.com/54585.html

上一篇下一篇

猜你喜欢

热点阅读