Java源码阅读之HashSet

HashSet是我们常用的一种数据结构。用来存储值唯一的集合。本文基于JDK1.8.0_151的Java源代码。

先来看看HashSet的类定义:

 /**
 * @author  Josh Bloch
 * @author  Neal Gafter
 * @see     Collection
 * @see     Set
 * @see     TreeSet
 * @see     HashMap
 * @since   1.2
 */

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable

类定义中的信息非常重要,包括注释都是非常重要的。作者有Josh Blosh大牛,也就是《Effective Java》的作者。

并且这个类是JDk1.2才开始出现的。

注意看那几个@see 注解,Collection接口,Set接口,以及TreeSet类和HashMap类。

我们先来分析一下HashSet的继承关系:

 可以看见HashSet在继承关系上和HashMap以及TreeSet没有什么直接关系,那为什么要@see 这两个类呢?

我们来看看HashSet的成员变量/常量:

    static final long serialVersionUID = -5024744406713321676L;

    private transient HashMap<E,Object> map;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();

两个成员常量,一个成员变量,注意map这个成员变量,这里HashMap出现了。

再来看看构造函数,这里我仅列举这么一个,因为其他构造函数除了输入参数不同外,全部都是为map赋值了一个HashMap对象。

    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }

而LinkedHashMap又是HashMap的子类。但是这个构造函数是包内可见,也就是说普通用户是无法使用的。

随后,我看了一下方法,明白了map的作用,这里仅列举add方法和iterator方法,大家就清楚了map和PRESENT的作用。

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
    public Iterator<E> iterator() {
        return map.keySet().iterator();
    }

简单说,就是HashSet本质是一个HashMap或者LinkedHashMap的keySet,对一个HashSet的一切操作其实都是对一个HashMap或者LinkedHashMap的操作。(普通用户无法让HashSet的本质是一个LinkedHashMap,构造函数包内可见已经说明了一切)

HashSet可以存储一个null值,并且遍历是无序的,当然这和HashMap是无序的有关系。可以说HashSet的特性基本是由HashMap来决定的。

【总结】:对于普通用户来说,HashSet本质就是一个HashMap的keySet,对HashSet的一切操作都是对一个HashMap操作。

猜你喜欢

转载自blog.csdn.net/guohengcook/article/details/81266964