jdk1.8.0_45源码解读——HashSet的实现

一、HashSet概述

  HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持。主要具有以下的特点:

  • 不保证set的迭代顺序,特别是它不保证该顺序恒久不变
  • 有且只允许一个null元素
  • 不允许有重复元素,这是因为HashSet是基于HashMap实现的,HashSet中的元素都存放在HashMap的key上面,而value中的值都是统一的一个private static final Object PRESENT = new Object();
  • 非同步的。如果多 个线程同时访问一个哈希set,而其中至少一个线程修改了该 set,那么它必须保持外部同步。这通常是通过对自然封装该set的对象执行同步操作来完成的。如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来“包装” set。最好在创建时完成这一操作,以防止对该set进行意外的不同步访问:
Set s = Collections.synchronizedSet(new HashSet(...));
  •    HashSet通过iterator()返回的迭代器是fail-fast的

 

二、HashSet源码解析

相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成。

1. HashSet类结构

//通过HashSet实现的接口可知,其支持所有集合操作,能被克隆,支持序列化
public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable
{
    static final long serialVersionUID = -5024744406713321676L;

    private transient HashMap<E,Object> map;

    //定义一个"虚拟"的static final Object对象作为HashMap的value
    private static final Object PRESENT = new Object();

    ......
}

HashSet包含了两个重要的成员变量:map, PRESENT。

(01) map是一个HashMap<E, Object>对象,HashSet是由一个HashMap实例支持的。

(02) PRESENT是一个static final Object对象,用来作为HashMap中的value值。

 

2. 构造函数

HashSet提供了四种方式的构造器,可以构造一个新的空 set,其底层 HashMap实例的默认初始容量是16,加载因子是 0.75,构造一个包含指定collection中的元素的新set,构造一个新的空set,其底层HashMap实例具有指定的初始容量和默认的加载因子(0.75),以及构造一个新的空set,其底层HashMap实例具有指定的初始容量和指定的加载因子。

    //默认的无参构造器,构造一个空的HashSet,实际底层会初始化一个空的HashMap,并使用默认初始容量为16和加载因子0.75。
    public HashSet() {
        map = new HashMap<E, Object>();
    }

    //构造一个包含指定collection中的元素的新set。
    //实际底层使用默认的加载因子0.75和足以包含指定collection中所有元素的初始容量来创建一个HashMap。
    public HashSet(Collection<? extends E> c) {
        map = new HashMap<E, Object>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);  //AbstractCollection.addAll(Collection<? extends E> c)
    }

    //以指定的初始容量和加载因子构造一个空的HashSet
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<E, Object>(initialCapacity, loadFactor);
    }

    //以指定的initialCapacity和默认加载因子0.75构造一个空的HashSet
    public HashSet(int initialCapacity) {
        map = new HashMap<E, Object>(initialCapacity);
    }

    /**
     * 以指定的initialCapacity和loadFactor构造一个新的空链接哈希集合
     * 此构造函数为包访问权限,不对外公开,实际只是是对LinkedHashSet的支持
     * 
     * @param      initialCapacity   初始容量
     * @param      loadFactor        加载因子
     * @param      dummy             标记,用于与其他的构造函数区分(可忽略)
     * @throws     IllegalArgumentException 如果初始容量小于零或加载因子为非正数
     */
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<E, Object>(initialCapacity, loadFactor);
    }
View Code

相关文章: