HashSet以及LinkedHashSet源码浅析

HashSet类定义
public class HashSet
    extends AbstractSet
    implements Set, Cloneable, java.io.Serializable{}

主要是继承了AbstractSet,实现了Set接口。

主要成员变量
    private transient HashMap map;
    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();

我们知道set是一个无重复元素的集合,那么元素到底是如何保存呢?实质是保存在一个HashMap里,这里使用的是map的key来保存元素,而map里面所有的value都是下方的PRESENT这个对象。

主要构造方法
  /**
     * Constructs a new, empty set; the backing HashMap instance has
     * default initial capacity (16) and load factor (0.75).
     */
    public HashSet() {
        map = new HashMap<>();
    }

    /**
     * Constructs a new set containing the elements in the specified
     * collection.  The HashMap is created with default load factor
     * (0.75) and an initial capacity sufficient to contain the elements in
     * the specified collection.
     *
     * @param c the collection whose elements are to be placed into this set
     * @throws NullPointerException if the specified collection is null
     */
    public HashSet(Collection c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }

    /**
     * Constructs a new, empty set; the backing HashMap instance has
     * the specified initial capacity and the specified load factor.
     *
     * @param      initialCapacity   the initial capacity of the hash map
     * @param      loadFactor        the load factor of the hash map
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero, or if the load factor is nonpositive
     */
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
    }

    /**
     * Constructs a new, empty set; the backing HashMap instance has
     * the specified initial capacity and default load factor (0.75).
     *
     * @param      initialCapacity   the initial capacity of the hash table
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero
     */
    public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }

HashSet的构造方法比较灵活,第一个是最简单的构造方法;第二个是使用一个Collection来初始化map,注意方法里调整了HashMap的初始容量;第三个是根据参数设定初始大小和loadFactor;第四种就是指定了初始大小。

主要方法
   /**
     * Adds the specified element to this set if it is not already present.
     * More formally, adds the specified element e to this set if
     * this set contains no element e2 such that
     * (e==null ? e2==null : e.equals(e2)).
     * If this set already contains the element, the call leaves the set
     * unchanged and returns false.
     *
     * @param e element to be added to this set
     * @return true if this set did not already contain the specified
     * element
     */
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

添加元素方法很简单,map.put(e, PRESENT)==null;,如果之前存在e了,那么返回false,如果不存在,返回true

/**
     * Removes the specified element from this set if it is present.
     * More formally, removes an element e such that
     * (o==null ? e==null : o.equals(e)),
     * if this set contains such an element.  Returns true if
     * this set contained the element (or equivalently, if this set
     * changed as a result of the call).  (This set will not contain the
     * element once the call returns.)
     *
     * @param o object to be removed from this set, if present
     * @return true if the set contained the specified element
     */
    public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
    }

删除元素方法也很简单,使用map.remove(o)即可。

 public boolean contains(Object o) {
        return map.containsKey(o);
    }

查询是否存在该元素。

public boolean isEmpty() {
        return map.isEmpty();
    }

HashSet是否为空

   /**
     * Returns an iterator over the elements in this set.  The elements
     * are returned in no particular order.
     *
     * @return an Iterator over the elements in this set
     * @see ConcurrentModificationException
     */
    public Iterator iterator() {
        return map.keySet().iterator();
    }

返回iterator。

注意的地方

HashSet就是使用HashMap实现的,HashMap不是线程安全的,HashSet同样也不是线程安全的,接下来需要分析HashMap这个类。

LinkedHashSet类定义
public class LinkedHashSet
    extends HashSet
    implements Set, Cloneable, java.io.Serializable {
}

可以看到,LinkedHashSet继承了HashSet,我们知道,LinkedHashSet是保持插入顺序的一种Set,那么是如何保证呢?请看构造方法。

主要构造方法
 public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
    }

    /**
     * Constructs a new, empty linked hash set with the specified initial
     * capacity and the default load factor (0.75).
     *
     * @param   initialCapacity   the initial capacity of the LinkedHashSet
     * @throws  IllegalArgumentException if the initial capacity is less
     *              than zero
     */
    public LinkedHashSet(int initialCapacity) {
        super(initialCapacity, .75f, true);
    }

    /**
     * Constructs a new, empty linked hash set with the default initial
     * capacity (16) and load factor (0.75).
     */
    public LinkedHashSet() {
        super(16, .75f, true);
    }

    /**
     * Constructs a new linked hash set with the same elements as the
     * specified collection.  The linked hash set is created with an initial
     * capacity sufficient to hold the elements in the specified collection
     * and the default load factor (0.75).
     *
     * @param c  the collection whose elements are to be placed into
     *           this set
     * @throws NullPointerException if the specified collection is null
     */
    public LinkedHashSet(Collection c) {
        super(Math.max(2*c.size(), 11), .75f, true);
        addAll(c);
    }

可以看到,构造方法均是调用了父类方法,具体是哪个父类方法呢?

   /**
     * Constructs a new, empty linked hash set.  (This package private
     * constructor is only used by LinkedHashSet.) The backing
     * HashMap instance is a LinkedHashMap with the specified initial
     * capacity and the specified load factor.
     *
     * @param      initialCapacity   the initial capacity of the hash map
     * @param      loadFactor        the load factor of the hash map
     * @param      dummy             ignored (distinguishes this
     *             constructor from other int, float constructor.)
     * @throws     IllegalArgumentException if the initial capacity is less
     *             than zero, or if the load factor is nonpositive
     */
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }

这个构造方法的说明里提到了,此方法仅提供给LinkedHashSet,里面是用LinkedHashMap来代替了HashMap。
HashSet和LinkedHashSet背后都是map,所以需要研究下map系列。

你可能感兴趣的:(HashSet以及LinkedHashSet源码浅析)