1. 程式人生 > >Java 集合系列16之 HashSet詳細介紹(原始碼解析)和使用示例

Java 集合系列16之 HashSet詳細介紹(原始碼解析)和使用示例

  1 package java.util;
  2 
  3 public class HashSet<E>
  4     extends AbstractSet<E>
  5     implements Set<E>, Cloneable, java.io.Serializable
  6 {
  7     static final long serialVersionUID = -5024744406713321676L;
  8 
  9     // HashSet是通過map(HashMap物件)儲存內容的
 10     private
transient HashMap<E,Object> map; 11 12 // PRESENT是向map中插入key-value對應的value 13 // 因為HashSet中只需要用到key,而HashMap是key-value鍵值對; 14 // 所以,向map中新增鍵值對時,鍵值對的值固定是PRESENT 15 private static final Object PRESENT = new Object(); 16 17 // 預設建構函式 18 public HashSet() { 19 //
呼叫HashMap的預設建構函式,建立map 20 map = new HashMap<E,Object>(); 21 } 22 23 // 帶集合的建構函式 24 public HashSet(Collection<? extends E> c) { 25 // 建立map。 26 // 為什麼要呼叫Math.max((int) (c.size()/.75f) + 1, 16),從 (c.size()/.75f) + 1 和 16 中選擇一個比較大的樹呢? 27 //
首先,說明(c.size()/.75f) + 1 28 // 因為從HashMap的效率(時間成本和空間成本)考慮,HashMap的載入因子是0.75。 29 // 當HashMap的“閾值”(閾值=HashMap總的大小*載入因子) < “HashMap實際大小”時, 30 // 就需要將HashMap的容量翻倍。 31 // 所以,(c.size()/.75f) + 1 計算出來的正好是總的空間大小。 32 // 接下來,說明為什麼是 16 。 33 // HashMap的總的大小,必須是2的指數倍。若建立HashMap時,指定的大小不是2的指數倍; 34 // HashMap的建構函式中也會重新計算,找出比“指定大小”大的最小的2的指數倍的數。 35 // 所以,這裡指定為16是從效能考慮。避免重複計算。 36 map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16)); 37 // 將集合(c)中的全部元素新增到HashSet中 38 addAll(c); 39 } 40 41 // 指定HashSet初始容量和載入因子的建構函式 42 public HashSet(int initialCapacity, float loadFactor) { 43 map = new HashMap<E,Object>(initialCapacity, loadFactor); 44 } 45 46 // 指定HashSet初始容量的建構函式 47 public HashSet(int initialCapacity) { 48 map = new HashMap<E,Object>(initialCapacity); 49 } 50 51 HashSet(int initialCapacity, float loadFactor, boolean dummy) { 52 map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor); 53 } 54 55 // 返回HashSet的迭代器 56 public Iterator<E> iterator() { 57 // 實際上返回的是HashMap的“key集合的迭代器” 58 return map.keySet().iterator(); 59 } 60 61 public int size() { 62 return map.size(); 63 } 64 65 public boolean isEmpty() { 66 return map.isEmpty(); 67 } 68 69 public boolean contains(Object o) { 70 return map.containsKey(o); 71 } 72 73 // 將元素(e)新增到HashSet中 74 public boolean add(E e) { 75 return map.put(e, PRESENT)==null; 76 } 77 78 // 刪除HashSet中的元素(o) 79 public boolean remove(Object o) { 80 return map.remove(o)==PRESENT; 81 } 82 83 public void clear() { 84 map.clear(); 85 } 86 87 // 克隆一個HashSet,並返回Object物件 88 public Object clone() { 89 try { 90 HashSet<E> newSet = (HashSet<E>) super.clone(); 91 newSet.map = (HashMap<E, Object>) map.clone(); 92 return newSet; 93 } catch (CloneNotSupportedException e) { 94 throw new InternalError(); 95 } 96 } 97 98 // java.io.Serializable的寫入函式 99 // 將HashSet的“總的容量,載入因子,實際容量,所有的元素”都寫入到輸出流中 100 private void writeObject(java.io.ObjectOutputStream s) 101 throws java.io.IOException { 102 // Write out any hidden serialization magic 103 s.defaultWriteObject(); 104 105 // Write out HashMap capacity and load factor 106 s.writeInt(map.capacity()); 107 s.writeFloat(map.loadFactor()); 108 109 // Write out size 110 s.writeInt(map.size()); 111 112 // Write out all elements in the proper order. 113 for (Iterator i=map.keySet().iterator(); i.hasNext(); ) 114 s.writeObject(i.next()); 115 } 116 117 118 // java.io.Serializable的讀取函式 119 // 將HashSet的“總的容量,載入因子,實際容量,所有的元素”依次讀出 120 private void readObject(java.io.ObjectInputStream s) 121 throws java.io.IOException, ClassNotFoundException { 122 // Read in any hidden serialization magic 123 s.defaultReadObject(); 124 125 // Read in HashMap capacity and load factor and create backing HashMap 126 int capacity = s.readInt(); 127 float loadFactor = s.readFloat(); 128 map = (((HashSet)this) instanceof LinkedHashSet ? 129 new LinkedHashMap<E,Object>(capacity, loadFactor) : 130 new HashMap<E,Object>(capacity, loadFactor)); 131 132 // Read in size 133 int size = s.readInt(); 134 135 // Read in all elements in the proper order. 136 for (int i=0; i<size; i++) { 137 E e = (E) s.readObject(); 138 map.put(e, PRESENT); 139 } 140 } 141 }