HashSet源码分析

基于jdk1.8进行分析的。

HashSet集合是不允许重复元素的,怎么保证的呢?结论是:HashSet是借助于HashMap的key不允许重复这个特性来实现的。HashMap是操作键值对,而HashSet是操作HashMap的key完成相关操作,或者这么说,HashSet全部的操作是借助于HashMap经过某种封装得到的。

继承结构

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

可以清楚的看到继承了AbstractSet类,实现了Set接口,Cloneable、Serializable接口。

构造函数

    //默认构造方法
    public HashSet() {
        //可见内部通过HashMap实现的
        map = new HashMap<>();
    }
    
    //通过集合创建HashSet,可见也是创建一个HashMap,通过addAll方法填充元素
    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);
    }
    
    //Constructs a new, empty linked hash set.
    //解释过来就是,创建一个新的空的hashSet
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }

通过上面的构造方法可以看到HashSet是通过有一个HashMap类型的map成员属性,通过操作HashMap实现的。

成员属性

    //序列化的时候使用
    static final long serialVersionUID = -5024744406713321676L;
    //成员属性map
    private transient HashMap<E,Object> map;
    //HashMap 为<key, value>的键值对, 既然HashSet的值就是HashMap的key,
    //那么HashMap的值呢,当然就是这个PRESENT啦
    private static final Object PRESENT = new Object();

成员方法

add(E e)

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

可见是通过调用map的put方法实现的。就是将要添加的元素作为map的key,常量PRESENT作为value保存在HashMap对象中即可。有一点需要我们注意的是:这个add方法有返回值,返回值由map的put方法决定。当map调用put(key,value)方法时,如果存在key后,则map的put方法会返回此key对应的oldValue,add就会返回false。

iterator()

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

HashSet并没有提供类似于get的方法,只提供的获取访问元素的迭代器对象。iterator方法也是委托给了map,获取map的key集合的迭代器。

其他方法

    public int size() {
        return map.size();
    }
    public boolean isEmpty() {
        return map.isEmpty();
    }
    public boolean contains(Object o) {
        return map.containsKey(o);
    }
    public void clear() {
        map.clear();
    }
    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }

可以看到都是通过操作map来实现的。剩下的方法如:readObject、writeObject、clone等方法就不再一一列举了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值