JAVA常用集合原始碼分析:HashSet
序言
在上一篇文章中,我們介紹了HashMap,其實本來想自己完成原始碼分析的一系列文章的,但是HashMap的原始碼著實是複雜,看的我腦殼疼。。於是就自己去找了找大牛們的文章反覆看,後面總算有了點門道了,大致知道了HashMap的原理,然後轉載了一篇我認為總結的比較好的文章到我的部落格裡,供大家一起學習。初步瞭解HashMap的原始碼後,自以為自己還OK了,於是便打算獨立把ConcurrentHashMap的原始碼也一併分析完,然後寫下來,可是一看程式碼行數
我。。。。給跪了orz 算了算了改天再來吧
HashSet
算了,回到正文,我們先來回想下HashSet是個啥?它也是個集合類(廢話...),可以儲存物件,但是儲存是無序的,不可以存取重複的物件...有了這些印象,我們就帶著問題來分析原始碼
- 為什麼是無序
- 為什麼不可以儲存重複物件
結構
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
沒有什麼特別的東西,很常用的繼承結構,一步一步慢慢分解下來,中間用抽象類來緩衝下面實現集合的工作量
實現的Set介面,這個是多餘的東西,可以不實現它,因為在AbstractSet中已經實現了set介面了,繼承了AbstractSet,就相當於也實現了Set介面
Cloneable
Serializable:能夠使之序列化
屬性
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
哇,巨簡單有木有!就兩個屬性!
根據這個屬性,我們也可以得出結論
HashSet的底層是由HashMap實現的
建構函式
public HashSet() { map = new HashMap<>(); } public HashSet(Collection<? extends E> c) { map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16)); addAll(c); } public HashSet(int initialCapacity, float loadFactor) { map = new HashMap<>(initialCapacity, loadFactor); } public HashSet(int initialCapacity) { map = new HashMap<>(initialCapacity); } HashSet(int initialCapacity, float loadFactor, boolean dummy) { map = new LinkedHashMap<>(initialCapacity, loadFactor); }
雖然建構函式有好幾個,但是都是initalCapacity(初始容量) loadFactor(負載因子)這些的組合而已,最後都是呼叫HashMap的構造方法對map進行初始化
常用方法
1.add(E)
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
這個方法是我們用的最多的方法,然鵝它的實現只有短短一行...這也進一步說明HashSet是靠底層的HashMap實現的。從這個方法中,我們可以發現set中的每一個值,都被當做一個key儲存在HashMap中,對應的value都是PRESENT,這也解釋了為什麼HashSet的值是不能重複的,因為map中的key是不能重複的,當有重複的值寫入到HashTree中,value值會被覆蓋,key值不受影響。
同樣,map中的值是無序的,所以TreeSet的值也是無序的啦。
2.remove(Object) 刪除一個物件
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
同樣是呼叫map的刪除方法,至於其他的一些方法,也都大同小異,就不展開敘述啦
3.為什麼沒有get(index) 這個方法
因為是無序的呀!
4.那麼要如何遍歷呢?
//增強for迴圈遍歷
for(String s: set){
System.out.println(s);
}
//迭代器遍歷
Iterator<String> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
總結
HashSet是我讀過最簡單的原始碼啦2333,畢竟複雜的操作都交給HashMap去實現啦,HashSet只要幾行程式碼呼叫下就ok,巨簡單
最後再回顧下HashSet的特點
- 元素沒有順序(底層用的是HashMap,HashMap本身中的元素度沒有順序,那麼HashSet更不可能有了)
- 元素不能重複(HashSet中存放的元素,度是當作HashMap的key來使用,HashMap中key是不能相同的,所以HashSet的元素也不能重複了)
- 非執行緒安全(HashMap有的問題它都有)