咱們已經分析了List接口下的ArrayList和LinkedList,以及Map接口下的HashMap、LinkedHashMap、TreeMap,接下來看的是Set接口下HashSet和LinkedHashSet,其實在分析完了HashMap、LinkedHashMap以後,再來看HashSet和LinkedHashSet就會很是簡單。html
四個關注點在hashSet上的答案java
由於hashSet的底層是基於hashMap,因此hashSet的數據結構就是hashMap的數據結構,由於前面已經分析過了hashMap的數據結構,這裏再也不贅述。集合之HashMap(含JDK1.8源碼分析)。數據結構
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); }
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 ? e2==null : 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 ? e==null : 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 ? e==null : 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就很簡單了。