對於 HashSet 而言,它是基於 HashMap 實現的,HashSet 底層採用 HashMap 來保存所有元素,因此 HashSet 的實現比較簡單,查看 HashSet 的源代碼,可以看到如下代碼:
(1)使用HashMap的key保存HashSet的元素。
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
// 使用 HashMap 的 key 保存 HashSet 中所有元素**************************
private transient HashMap<E,Object> map;
// 定義一個虛擬的 Object 對象作爲 HashMap 的 value ********************
private static final Object PRESENT = new Object();
...
// 初始化 HashSet,底層會初始化一個 HashMap
public HashSet()
{
map = new HashMap<E,Object>();
}
// 以指定的 initialCapacity、loadFactor 創建 HashSet
// 其實就是以相應的參數創建 HashMap
public HashSet(int initialCapacity, float loadFactor)
{
map = new HashMap<E,Object>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity)
{
map = new HashMap<E,Object>(initialCapacity);
}
HashSet(int initialCapacity, float loadFactor, boolean dummy)
{
map = new LinkedHashMap<E,Object>(initialCapacity
, loadFactor);
}
// 調用 map 的 keySet 來返回所有的 key **************
public Iterator<E> iterator()
{
return map.keySet().iterator();
}
// 調用 HashMap 的 size() 方法返回 Entry 的數量,就得到該 Set 裏元素的個數
public int size()
{
return map.size();
}
// 調用 HashMap 的 isEmpty() 判斷該 HashSet 是否爲空,
// 當 HashMap 爲空時,對應的 HashSet 也爲空
public boolean isEmpty()
{
return map.isEmpty();
}
// 調用 HashMap 的 containsKey 判斷是否包含指定 key
//HashSet 的所有元素就是通過 HashMap 的 key 來保存的
public boolean contains(Object o)
{
return map.containsKey(o);
}
// 將指定元素放入 HashSet 中,也就是將該元素作爲 key 放入 HashMap
public boolean add(E e)
{
return map.put(e, PRESENT) == null;
}
// 調用 HashMap 的 remove 方法刪除指定 Entry,也就刪除了 HashSet 中對應的元素
public boolean remove(Object o)
{
return map.remove(o)==PRESENT;
}
// 調用 Map 的 clear 方法清空所有 Entry,也就清空了 HashSet 中所有元素
public void clear()
{
map.clear();
}
...
}
由上面源程序可以看出,HashSet 的實現其實非常簡單,它只是封裝了一個 HashMap 對象來存儲所有的集合元素,所有放入 HashSet 中的集合元素實際上由 HashMap 的 key 來保存,而 HashMap 的 value 則存儲了一個 PRESENT,它是一個靜態的 Object 對象。
HashSet 的絕大部分方法都是通過調用 HashMap 的方法來實現的,因此 HashSet 和 HashMap 兩個集合在實現本質上是相同的。
2.因爲HashSet底層是HashMap這也就說明了以下HashSet的幾個特性:
(1)HashSet是無序的
(2)HashSet是不同步的
(3)元素集合可以爲null,但只能一個爲空,以及set是不重複的集合。
(4)hashcode是比對key值,value不用比較。
是否相等:hashcode相等---同一個bucket,且equals(key)相等。
3.LinkedHashSet
HashSet的子類,也是通過hashcode定位bucket,然後通過equals判斷是否相等,只是多了一個鏈表來記錄添加元素的順序。所以輸出元素的順序總是與添加順序一致。
4.TreeSet(所有元素必須實現Comparable接口,底層紅黑樹)
是SortedSet接口的實現類,按照升序排序。也可以採用定製排序 Comparator 的comparator()。
自然排序,默認的就是Comparator裏面的compareTo()方法進行比較。
TreeSet是基於TreeMap實現的。TreeSet中的元素支持2種排序方式:自然排序
或者 根據創建TreeSet 時提供的 Comparator 進行排序。這取決於使用的構造方法。
TreeSet爲基本操作(add、remove 和 contains)提供受保證的 log(n) 時間開銷
是否相等:compareTo(o1,o2)返回值是否爲0,不考慮equals。所以即使equals爲true,但compareTo返回值不是0,那麼兩個對象也不相等。
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
{
// NavigableMap對象*********基於TreeMap實現的
private transient NavigableMap<E,Object> m;
// TreeSet是通過TreeMap實現的,
// PRESENT是鍵-值對中的值。
private static final Object PRESENT = new Object();
// 不帶參數的構造函數。創建一個空的TreeMap
public TreeSet() {
this(new TreeMap<E,Object>());
}
// 將TreeMap賦值給 "NavigableMap對象m"
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
// 帶比較器的構造函數。
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<E,Object>(comparator));
}