zoukankan      html  css  js  c++  java
  • 集合之HashSet(含JDK1.8源码分析)

    一、前言

      我们已经分析了List接口下的ArrayList和LinkedList,以及Map接口下的HashMap、LinkedHashMap、TreeMap,接下来看的是Set接口下HashSet和LinkedHashSet,其实在分析完了HashMap、LinkedHashMap之后,再来看HashSet和LinkedHashSet就会非常简单。

      四个关注点在hashSet上的答案

    二、hashSet的数据结构

      因为hashSet的底层是基于hashMap,所以hashSet的数据结构就是hashMap的数据结构,因为前面已经分析过了hashMap的数据结构,这里不再赘述。集合之HashMap(含JDK1.8源码分析)

    三、hashSet源码分析-属性及构造函数

      3.1 类的继承关系

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

      说明:实现了Set接口,其内定义了一些共有的操作。

      3.2 类的属性

        //版本序列号       
        static final long serialVersionUID = -5024744406713321676L;
        
        //基于map的操作
        private transient HashMap<E,Object> map;
    
        // Dummy value to associate with an Object in the backing Map
        private static final Object PRESENT = new Object();

      说明:hashSet的底层是基于hashMap或linkedHashMap的,所以定义了一个HashMap的属性,又因为map是基于键值对来进行操作的,所以又定义了一个假的key-value中的value:PRESENT,注意此属性被final修饰,即值永远不会被改变,仅仅是在map操作时补一下value的位置。所有通过hashSet添加进来的key都对应同一个value值,PRESENT。

      3.3 类的构造函数

      

      如上所述,共有五种。这里说明一下hashSet下定义的基于两种不同的map操作的构造函数。

       1、HashSet()型

    /**
         * 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<>();
        }

      说明:底层基于hashMap进行操作,红框中剩下的三种也是基于hashMap操作的。

      2、HashSet(int initialCapacity, float loadFactor, boolean dummy)

    /**
         * 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);
        }

      说明:注意该构造方法不是public的,且注释中已经说该构造方法只会被LinkedHashSet使用,所以平常我们new HashSet的时候是不能用的,该方法只有在创建LinkedHashSet对象的时候:new LinkedHashSet()才会被调用,如下super(16, .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);
        }

    四、hashSet源码分析-核心函数

      hashSet的add方法,contains方法,remove方法等等都是基于hashMap的操作方式,前面已经分析过,这里不再赘述。

      4.1 add方法

    /**
         * 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;
        }

      4,2 remove方法

    /**
         * 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;
        }

      4.3 contains方法

    /**
         * Returns <tt>true</tt> if this set contains the specified element.
         * More formally, returns <tt>true</tt> if and only if this set
         * contains an element <tt>e</tt> such that
         * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
         *
         * @param o element whose presence in this set is to be tested
         * @return <tt>true</tt> if this set contains the specified element
         */
        public boolean contains(Object o) {
            return map.containsKey(o);
        }

      举例:

    public class Test {
        public static void main(String[] args) {
            HashSet hashSet = new HashSet<>();
            hashSet.add("zs");
            hashSet.add("ls");
            hashSet.add("ww");
            hashSet.add("zl");
            hashSet.add(null);
            hashSet.add("zs");
            System.out.println(hashSet);
            boolean zs1 = hashSet.remove("zs");
            System.out.println("删除zs===" + zs1);
            System.out.println(hashSet);
            boolean zs = hashSet.contains("zs");
            System.out.println("是否包含zs===" + zs);
        }
    }

      结果:可见,hashSet允许空值,不允许重复数据,无序。

    [ww, null, zl, ls, zs]
    删除zs===true
    [ww, null, zl, ls]
    是否包含zs===false

    五、总结

      可见,hashSet是与hashMap相对应的,分析完hashMap再来看hashSet就很简单了。

  • 相关阅读:
    并发的简单介绍1
    UITableView (4): 在TableView中移动cell和Section 从TableView中删除cell和section 添加系统默认刷新控件
    UITableView (3):显示cell上的菜单
    TableView(2)
    UITableView (1)
    在 Interface Builder 中配置自动布局的约束
    Velocity 的工作原理
    ORA-01858: a non-numeric character was found where a numeric was expected
    Java 8:不要再用循环了
    Lambda表达式
  • 原文地址:https://www.cnblogs.com/zfyang2429/p/10455569.html
Copyright © 2011-2022 走看看