美文网首页
HashSet以及LinkedHashSet源码浅析

HashSet以及LinkedHashSet源码浅析

作者: lvlvforever | 来源:发表于2018-06-24 13:58 被阅读0次
    HashSet类定义
    public class HashSet<E>
        extends AbstractSet<E>
        implements Set<E>, Cloneable, java.io.Serializable{}
    

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

    主要成员变量
        private transient HashMap<E,Object> 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 <tt>HashMap</tt> 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 <tt>HashMap</tt> 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<? extends E> c) {
            map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
            addAll(c);
        }
    
        /**
         * Constructs a new, empty set; the backing <tt>HashMap</tt> 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 <tt>HashMap</tt> 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 <tt>e</tt> to this set if
         * this set contains no element <tt>e2</tt> such that
         * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
         * If this set already contains the element, the call leaves the set
         * unchanged and returns <tt>false</tt>.
         *
         * @param e element to be added to this set
         * @return <tt>true</tt> 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 <tt>e</tt> such that
         * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>,
         * if this set contains such an element.  Returns <tt>true</tt> 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 <tt>true</tt> 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<E> iterator() {
            return map.keySet().iterator();
        }
    

    返回iterator。

    注意的地方

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

    LinkedHashSet类定义
    public class LinkedHashSet<E>
        extends HashSet<E>
        implements Set<E>, 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<? extends E> 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源码浅析

          本文链接:https://www.haomeiwen.com/subject/kenjyftx.html