Java容器HashSet和LinkedHashSet源代码解析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Kevin_zhai/article/details/72779778

写在前面的话

本文针对的是Java1.6进行的源码分析,与其他版本可能存在差异。

概述

HashSet和LinkedHashSet分别是用HashMap和LinkedHashMap来实现的,它们是把数据作为Key值存入到HashMap或LinkedHashMap中。因此Set都不允许有重复的值,且HashSet是无序的,LinkedHashSet是有序的。之前,已经介绍过HashMap和LinkedHashMap的相关内容了,可以分别参考Java容器HashMap源代码解析Java容器LinkedHashMap源代码解析

源代码解析

LinkedHashSet是继承自HashSet的,因此,我们先看HashSet的源代码。

属性和构造方法

    //用于存放数据
    private transient HashMap<E,Object> map;

    //存放到HashMap中的值
    private static final Object PRESENT = new Object();

    //默认构造方法,新建一个容量为16,加载因子为0.75的HashMap
    public HashSet() {
        map = new HashMap<E,Object>();
    }

    //带有collection参数的构造方法
    public HashSet(Collection<? extends E> c) {
        map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }

    //给定容量和加载因子的构造方法
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<E,Object>(initialCapacity, loadFactor);
    }

    //给定容量的构造方法
    public HashSet(int initialCapacity) {
        map = new HashMap<E,Object>(initialCapacity);
    }

    //多了dummy参数,在LinkedHashSet会用这个构造方法
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
    }

带有collection参数的构造函数用到了addAll方法,在HashSet中并没有重写这个方法,因此这里直接用的AbstractCollection中的该方法。代码如下:

    public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        Iterator<? extends E> e = c.iterator();
        //遍历collection迭代器
        while (e.hasNext()) {
            //调用相应容器的add方法
            if (add(e.next()))
            modified = true;
        }
        return modified;
    }

在HashSet中定义了两个属性,map用于存放数据,PRESENT 是往map中存放数据时,默认的value值。它有五个构造方法,前四个都是调用HashMap的对应构造方法来初始化map。最后一个多了dummy函数,是提供给LinkedHashSet用的,LinkedHashSet通过调用LinkedHashMap的构造方法来初始化map。

其它方法

    //迭代器,因为HashSet相当于对HashMap的key进行遍历,所以直接返回
    //map中keySet的迭代器即可。因此HashSet也是无序的。
    public Iterator<E> iterator() {
        return map.keySet().iterator();
    }

    //返回大小,直接返回map的大小即可
    public int size() {
        return map.size();
    }

    //判断是否为空,也就是判断map是否为空
    public boolean isEmpty() {
        return map.isEmpty();
    }

    //判断是否包含某个值,直接调用map的containsKey方法
    public boolean contains(Object o) {
        return map.containsKey(o);
    }

    //添加元素,直接调用map的put方法
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

    //删除元素,直接调用map的remove方法
    public boolean remove(Object o) {
    return map.remove(o)==PRESENT;
    }

    //情空Set,直接调用map的清空方法
    public void clear() {
        map.clear();
    }

    //拷贝set
    public Object clone() {
        try {
            HashSet<E> newSet = (HashSet<E>) super.clone();
            newSet.map = (HashMap<E, Object>) map.clone();
            return newSet;
        } catch (CloneNotSupportedException e) {
            throw new InternalError();
        }
    }

HashSet提供的这些方法都是通过调用HashMap的对应方法来实现的,在这里不再详述,如果不熟悉HashMap中这些方法的具体实现,请参考文章开头提到的两篇博文。

LinkedHashSet构造方法

介绍完了HashSet,我们再看一下LinkedHashSet的具体实现。LinkedHashSet是继承自HashSet的,它本身只提供了四个构造方法,都是通过调用HashSet最后一个构造函数来实现的。代码如下:

    //给定map容量和加载因子的构造方法
    public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
    }

    //给定容量的构造方法,加载因子默认用0.75
    public LinkedHashSet(int initialCapacity) {
        super(initialCapacity, .75f, true);
    }

    //默认构造方法,容量用默认值16,加载因子用默认值0.75
    public LinkedHashSet() {
        super(16, .75f, true);
    }

    //带有collection参数的构造方法
    public LinkedHashSet(Collection<? extends E> c) {
        super(Math.max(2*c.size(), 11), .75f, true);
        addAll(c);
    }

猜你喜欢

转载自blog.csdn.net/Kevin_zhai/article/details/72779778