HashSet
此類由一個(gè)哈希表(實(shí)際上是一個(gè)HashMap實(shí)例)支持本缠。 不保證元素的順序,特別是逞度,它不保證順序隨著時(shí)間的推移保持不變悍手。該集合沒(méi)有重復(fù)的元素并且允許使用null元素。另外悠轩,跟之前分析的其他集合類一樣间狂,它是非同步的。
定義及說(shuō)明
定義如下:
public class HashSet<E> extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable{}
1火架、繼承了AbstractSet并實(shí)現(xiàn)了Set接口鉴象,即擁有Set基本的方法和屬性
2、實(shí)現(xiàn)了Cloneable何鸡,即支持clone
3纺弊、實(shí)現(xiàn)了java.io.Serializable,即支持序列化和反序列化
構(gòu)造函數(shù)如下:
//底層map
private transient HashMap<E,Object> map;
//構(gòu)造一個(gè)新的空HashSet骡男,底層HashMap實(shí)例的具有默認(rèn)初始容量(16)和加載因子(0.75)
public HashSet() {
map = new HashMap<>();
}
//構(gòu)造一個(gè)包含指定集合中元素的新HashSet淆游。 使用默認(rèn)加載因子(0.75)創(chuàng)建HashMap,初始容量要求足以包含指定集合中的元素
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
//構(gòu)造一個(gè)空的新HashSet隔盛,底層HashMap具有指定的初始容量和加載因子
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
//構(gòu)造一個(gè)新的空HashSet犹菱,底層HashMap實(shí)例具有指定的初始容量和默認(rèn)加載因子(0.75)
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
//構(gòu)造一個(gè)新的空HashSet。(此包私有構(gòu)造函數(shù)僅由LinkedHashSet使用)吮炕。底層HashMap實(shí)例是具有指定初始容量和指定加載因子的LinkedHashMap腊脱。
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
我們發(fā)現(xiàn),其實(shí)實(shí)例化一個(gè)HashSet的本質(zhì)就是實(shí)例化一個(gè)HashMap龙亲,所以說(shuō)陕凹,HashSet是由HashMap支持的。這里第二個(gè)構(gòu)造函數(shù)中鳄炉,有一個(gè)計(jì)算"Math.max((int) (c.size()/.75f) + 1, 16)"杜耙,這是因?yàn)镠ashMap的大小必須是2的指數(shù)倍,通過(guò)"c.size()/.75f"計(jì)算出來(lái)的實(shí)際大小跟16相比迎膜,如果小于16泥技,就直接使用16作為初始值,避免一些重復(fù)的計(jì)算磕仅。
源碼簡(jiǎn)析
我們看一下它的一些基本方法:
//與底層Map中的Object關(guān)聯(lián)的虛擬值
private static final Object PRESENT = new Object();
//返回此set中元素的迭代器
public Iterator<E> iterator() {
return map.keySet().iterator();
}
//獲取大小
public int size() {
return map.size();
}
//判空
public boolean isEmpty() {
return map.isEmpty();
}
//判斷是否包含指定元素
public boolean contains(Object o) {
return map.containsKey(o);
}
//添加元素
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
//刪除元素
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
//清空集合
public void clear() {
map.clear();
}
我們可以看到珊豹,他所有的基本方法都是通過(guò)調(diào)用HashMap對(duì)應(yīng)的方法來(lái)實(shí)現(xiàn)的,它的元素就是底層HashMap的key榕订,而底層HashMap的值都是一個(gè)Object類型的PRESENT對(duì)象店茶。
LinkedHashSet
Set接口的哈希表和鏈表實(shí)現(xiàn),具有可預(yù)測(cè)的迭代順序劫恒。此實(shí)現(xiàn)與HashSet的不同之處在于它維護(hù)了一個(gè)貫穿其所有條目的雙向鏈表贩幻。此鏈接列表定義迭代排序轿腺,即元素插入集合(插入順序)的順序。請(qǐng)注意丛楚,如果將元素重新插入到集合中族壳,則不會(huì)影響插入順序。(如果s.contains(e)在調(diào)用之前立即返回true趣些,則在調(diào)用s.add(e)時(shí)仿荆,將元素e重新插入到集合中)。該集合允許使用null元素坏平,且該集合是非同步的拢操。
定義及說(shuō)明
定義如下:
public class LinkedHashSet<E>
extends HashSet<E>
implements Set<E>, Cloneable, java.io.Serializable {}
1、它是繼承了HashSet并實(shí)現(xiàn)了Set接口舶替,所以具有Set基本的方法和屬性
2令境、實(shí)現(xiàn)了Cloneable,即支持clone
3顾瞪、實(shí)現(xiàn)了java.io.Serializable舔庶,即支持序列化和反序列化
構(gòu)造方法有:
//使用指定的初始容量和加載因子構(gòu)造一個(gè)新的空LinkedHashSet
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);
}
//使用指定的初始容量和默認(rèn)加載因子(0.75)構(gòu)造一個(gè)新的空鏈?zhǔn)焦<疞inkedHashSet
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true);
}
//使用默認(rèn)初始容量(16)和加載因子(0.75)構(gòu)造一個(gè)新的空LinkedHashSet
public LinkedHashSet() {
super(16, .75f, true);
}
//構(gòu)造一個(gè)新的LinkedHashSet,其具有與指定集合相同的元素玲昧。 創(chuàng)建鏈接的哈希集的初始容量足以容納指定集合中的元素栖茉,具有默認(rèn)加載因子(0.75)
public LinkedHashSet(Collection<? extends E> c) {
super(Math.max(2*c.size(), 11), .75f, true);
addAll(c);
}
我們可以發(fā)現(xiàn)篮绿,它其實(shí)就是通過(guò)調(diào)用HashSet的構(gòu)造方法來(lái)進(jìn)行實(shí)例化孵延。它和HashSet的區(qū)別就在于LinkedHashSet的元素是按照放入順序進(jìn)行排列。并且LinkedHashSet內(nèi)部使用LinkedHashMap實(shí)現(xiàn)亲配。
其他方法:
@Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);
}
它只重寫了HashSet的spliterator()方法(這個(gè)方法后期分析)尘应。
TreeSet
基于TreeMap的NavigableSet實(shí)現(xiàn)。元素使用其可比較的自然順序或在創(chuàng)建時(shí)創(chuàng)建時(shí)提供的Comparator進(jìn)行排序吼虎,具體取決于使用的構(gòu)造函數(shù)犬钢。它的基本操作(add、remove思灰、和contains)的時(shí)間復(fù)雜度為log(n)玷犹。當(dāng)然,它也是非同步的洒疚,不過(guò)不支持null元素歹颓。
定義及說(shuō)明
定義如下:
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable{}
1、繼承與AbstractSet油湖,實(shí)現(xiàn)了NavigableSet接口巍扛,即擁有Set的基本的方法和屬性。其元素使用其可比較的自然順序乏德,或者通過(guò)在創(chuàng)建時(shí)提供的Comparator進(jìn)行排序撤奸。
2吠昭、實(shí)現(xiàn)了Cloneable,即支持clone
3胧瓜、實(shí)現(xiàn)了java.io.Serializable矢棚,即支持序列化和反序列化
構(gòu)造函數(shù):
//底層映射
private transient NavigableMap<E,Object> m;
//構(gòu)造由指定的可導(dǎo)航映射支持的TreeSet
TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
//構(gòu)造一個(gè)新的空TreeSet,根據(jù)其元素的自然順序進(jìn)行排序府喳。 插入集合中的所有元素都必須實(shí)現(xiàn)Comparable接口幻妓。 此外,所有這些元素必須是可相互比較的
public TreeSet() {
this(new TreeMap<E,Object>());
}
//構(gòu)造一個(gè)新的空TreeSet劫拢,根據(jù)指定的比較器進(jìn)行排序肉津。 插入到集合中的所有元素必須通過(guò)指定的比較器相互比較
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
//構(gòu)造一個(gè)新的TreeSet,其中包含指定集合中的元素舱沧,并根據(jù)其元素的自然順序進(jìn)行排序妹沙。 插入集合中的所有元素都必須實(shí)現(xiàn)Comparable接口
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
//構(gòu)造一個(gè)包含相同元素并使用與指定有序集相同排序的新TreeSet
public TreeSet(SortedSet<E> s) {
this(s.comparator());
addAll(s);
}
可以看出,TreeSet是基于TreeMap實(shí)現(xiàn)的熟吏。在addAll()方法中距糖,其實(shí)也是調(diào)用了TreeMap進(jìn)行元素的添加。
源碼簡(jiǎn)析
再看一下一些基本的方法:
private static final Object PRESENT = new Object();
public boolean isEmpty() {
return m.isEmpty();
}
public boolean contains(Object o) {
return m.containsKey(o);
}
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return m.remove(o)==PRESENT;
}
public void clear() {
m.clear();
}
它也是通過(guò)調(diào)用Map的相關(guān)的方法牵寺,來(lái)實(shí)現(xiàn)功能悍引。它的元素就是底層Map的key,而底層Map的值都是一個(gè)Object類型的PRESENT對(duì)象帽氓。
小結(jié)
好了趣斤,到這就分析完了,總結(jié)一下:
Set集合中黎休,不允許有重復(fù)的元素浓领。且Set對(duì)兩個(gè)元素的比較不是使用"=="而是使用"equals"。HashSet和TreeSet是根據(jù)元素的自然順序或者構(gòu)建時(shí)傳入的Comparator比較器對(duì)元素進(jìn)行排序势腮,而LinkedHashSet是根據(jù)元素的插入順序進(jìn)行排序联贩。HashSet和LinkedHashSet允許有null元素,但是TreeSet不允許捎拯。