集合之HashSet(含JDK1.8源码分析)

1、前言

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

  四个关注点在hashSet上的答案java

2、hashSet的数据结构

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

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

  3.1 类的继承关系less

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。ui

  3.3 类的构造函数this

  

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

   一、HashSet()型code

/** * 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操做的。

  二、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); }

4、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

5、总结

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

相关文章
相关标签/搜索