HashSet源码分析

Set集合的最主要特性就是没有重复元素,HashSet是Set的一个字类,其内部基于HashMap实现

1. 成员变量

    private transient HashMap<E,Object> map;

    private static final Object PRESENT = new Object();

可以看到HashSet内部有一个HashMap, 但是PRESENT是干什么用的?HashMap是key-value形式的,但是Set是存储的是单一值,那么内部想要借由HashMap来实现的话,就必须有一个固定的value值,即HashSet中存放的每一个值在HashMap中作为key值,对应的value值都固定为PRESENT对象

2. 构造函数


    public HashSet() {
        map = new HashMap<>();
    }
    
    public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }
    
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
    }
    
    public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }
    
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }

一般起我们最常用的就是空参构造函数,在空参函数中会调用HashMap的空参构造函数, 由HashMap源码分析可以知道,空参构造函数的HashMap初始容量为4

3. 方法

3.1 add

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

在HashMap中,如果key值没有hash碰撞或者在冲突的链表上没有相同的key,HashMap.put会返回null, 否则会返回被替换的旧值,而由于HashSet中,所有key值对应的value都是PRESENT对象,这样就算在HashMap中有相等的key值,更新的也只是PRESENT,并没有在HashMap中插入新的key值,从而保证了HashSet中值的唯一性

3.2 remove

    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }

HashMap.remove如果删除成功,会返回对应的value,如果不存在对应的entry则返回null, 而HashSet中所有key值对应的value固定都是PRESENT

3.3 iterator

    public Iterator<E> iterator() {
        return map.keySet().iterator();
    }

推荐阅读更多精彩内容