學習JDK8源碼之--HashSet
阿新 • • 發佈:2019-05-10
mat res ont iterator 參數 one 包括 ray trac 類中的任何實現(包括add()方法)。它僅僅添加了 equals 和 hashCode 的實現。
1. HashSet簡介
HashSet是一個不可重復的無序集合,底層由HashMap實現存儲,故HashSet是非線程安全的,由於HashSet使用HashMap的Key來存儲元素,而HashMap的Key可以允許有一個null值,所以HashSet是可以存儲null值的。
由於HashSet的不可重復性,在項目開發中可以利用這一點進行元素去重,但前提是在不考慮線程安全的問題基礎上。
2. HashSet的繼承關系
HashSet繼承自AbstractSet,實現了Set、Cloneable、java.io.Serializable接口。
AbstractSet繼承自AbstractCollection,實現了Set接口,此類並沒有重寫 AbstractCollection
實現了Set接口:表明本類是一個不包含重復元素的類,並最多包含一個null值。
實現了Cloneable接口:可以調用Object.clone方法返回該對象的淺拷貝。
實現了 java.io.Serializable 接口:可以啟用其序列化功能,能通過序列化去傳輸。
3. HashSet的實現
1. 核心屬性
//HashMap存儲數據 private transient HashMap<E,Object> map; //final修飾的不可改變的空對象private static final Object PRESENT = new Object();
底層通過HashMap來進行數據的存儲,HashMap的key來存儲元素,value統一存儲一個不可改變的空對象PRESENT,為什麽要這麽做呢?因為既然是通過HashMap存儲數據,數據的移除操作也是通過HashMap的remove方法進行移除,而HashMap的remove方法會返回被移除的Value值,而把PRESENT設為final就能保證可以通過判斷返回的值是否是PRESENT對象就可以判斷是否移除成功。
2. 構造函數
//無參構造,實例化一個HashMap對象public HashSet() { map = new HashMap<>(); } //帶參構造,傳入一個集合 public HashSet(Collection<? extends E> c) { //因為HashMap的默認加載因子是0.75,當元素個數達到容量的0.75倍的時候便會自動擴容 //所以,這裏取(int) (c.size()/.75f) + 1,為了避免實例化後的HashMap達到默認尺度 //因為HashMap的默認初始容量是16,所以取(int) (c.size()/.75f) + 1和16的最大值作為初始容量 map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } //帶參構造,傳入一個HashMap的初始容量 public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } //帶參構造,傳入HashMap的初始容量和加載因子 public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } //帶參構造,傳入HashMap的初始容量和加載因子,dummy參數用來和上一個構造函數作區分,表明實例化一個LinkedHashMap HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
3. 核心方法
//添加一個元素 public boolean add(E e) { //調用HashMap的put方法,因為HashMap的Key不能重復,重復時會把添加的元素直接返回,成功則返回null return map.put(e, PRESENT)==null; } //調用HashMap的clear方法來清空元素 public void clear() { map.clear(); } //調用HashMap的containsKey來判斷是否包含元素o public boolean contains(Object o) { return map.containsKey(o); } //通過調用HashMap的isEmpty方法來判斷集合是否為空 public boolean isEmpty() { return map.isEmpty(); } //返回叠代器 public Iterator<E> iterator() { return map.keySet().iterator(); } //調用HashMap的remove方法來移除元素 public boolean remove(Object o) { return map.remove(o)==PRESENT; } //HashMap的大小就是集合的大小 public int size() { return map.size(); }
HashSet的基本元素操作都是通過調用HashMap的API來實現的,所以需要了解具體實現細節需要去學習HashMap。
4. HashSet的遍歷
1. 通過Iterator叠代器
// 假設set是HashSet對象 for(Iterator iterator = set.iterator(); iterator.hasNext(); ) { iterator.next(); }
2. foreach
// 假設set是HashSet對象,並且set中元素是String類型 String[] arr = (String[])set.toArray(new String[0]); for (String str:arr) System.out.println("for each : %s", str);
學習JDK8源碼之--HashSet