jdk源码分析——HashSet

Posted 自由水鸟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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了。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源码。


以上是关于jdk源码分析——HashSet的主要内容,如果未能解决你的问题,请参考以下文章

JDK源码分析——HashSet

jdk源码分析——HashSet

集合之HashSet(含JDK1.8源码分析)

HashSet源码分析 jdk1.6

Java提高篇——通过分析 JDK 源代码研究 Hash 存储机制

JDK源码分析-Collection