HashSet和TreeSet

對於 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));
      }


發佈了369 篇原創文章 · 獲贊 104 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章