HashSet:哈希表是通過(guò)使用稱為散列法的機(jī)制來(lái)存儲(chǔ)信息的,元素并沒(méi)有以某種特定順序來(lái)存放;
LinkedHashSet:以元素插入的順序來(lái)維護(hù)集合的鏈接表,允許以插入的順序在集合中迭代;
TreeSet:提供一個(gè)使用樹結(jié)構(gòu)存儲(chǔ)Set接口的實(shí)現(xiàn),對(duì)象以升序順序存儲(chǔ),訪問(wèn)和遍歷的時(shí)間很快。
(來(lái)源:深入Java集合學(xué)習(xí)系列:HashSet的實(shí)現(xiàn)原理)
不保證set的迭代順序,特別是它不保證該順序恒久不變。此類允許使用null元素。
對(duì)于HashSet而言,它是基于HashMap實(shí)現(xiàn)的,HashSet底層使用HashMap來(lái)保存所有元素,因此HashSet 的實(shí)現(xiàn)比較簡(jiǎn)單,相關(guān)HashSet的操作,基本上都是直接調(diào)用底層HashMap的相關(guān)方法來(lái)完成。
當(dāng)向HashSet結(jié)合中存入一個(gè)元素時(shí),HashSet會(huì)調(diào)用該對(duì)象的hashCode()方法來(lái)得到該對(duì)象的hashCode值,然后根據(jù) hashCode值來(lái)決定該對(duì)象在HashSet中存儲(chǔ)位置。
簡(jiǎn)單的說(shuō),HashSet集合判斷兩個(gè)元素相等的標(biāo)準(zhǔn)是兩個(gè)對(duì)象通過(guò)equals方法比較相等,并且兩個(gè)對(duì)象的hashCode()方法返回值相等
注意,如果要把一個(gè)對(duì)象放入HashSet中,重寫該對(duì)象對(duì)應(yīng)類的equals方法,也應(yīng)該重寫其hashCode()方法。其規(guī)則是如果兩個(gè)對(duì) 象通過(guò)equals方法比較返回true時(shí),其hashCode也應(yīng)該相同。另外,對(duì)象中用作equals比較標(biāo)準(zhǔn)的屬性,都應(yīng)該用來(lái)計(jì)算 hashCode的值。
public Iterator iterator() {
return map.keySet().iterator();
}
size()返回此 set 中的元素的數(shù)量(set 的容量)。底層調(diào)用HashMap的size方法,返回HashMap容器的大小。
public int size() {
return map.size();
}
isEmpty(),判斷HashSet()集合是否為空,為空返回 true,否則返回false。
public boolean isEmpty() {
return map.isEmpty();
}
contains(),判斷某個(gè)元素是否存在于HashSet()中,存在返回true,否則返回false。更加確切的講應(yīng)該是要滿足這種關(guān)系才能返回true:(onull ? enull : o.equals(e))。底層調(diào)用containsKey判斷HashMap的key值是否為空。
public boolean contains(Object o) {
return map.containsKey(o);
}
add()如果此 set 中尚未包含指定元素,則添加指定元素。如果此Set沒(méi)有包含滿足(enull ? e2null : e.equals(e2)) 的e2時(shí),則將e2添加到Set中,否則不添加且返回false。由于底層使用HashMap的put方法將key = e,value=PRESENT構(gòu)建成key-value鍵值對(duì),當(dāng)此e存在于HashMap的key中,則value將會(huì)覆蓋原有value,但是key保持不變,所以如果將一個(gè)已經(jīng)存在的e元素添加中HashSet中,新添加的元素是不會(huì)保存到HashMap中,所以這就滿足了HashSet中元素不會(huì)重復(fù)的特性。
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
remove如果指定元素存在于此 set 中,則將其移除。底層使用HashMap的remove方法刪除指定的Entry。
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
clear從此 set 中移除所有元素。底層調(diào)用HashMap的clear方法清除所有的Entry。
public void clear() {
map.clear();
}
clone返回此 HashSet 實(shí)例的淺表副本:并沒(méi)有復(fù)制這些元素本身。
public Object clone() {
try {
HashSet newSet = (HashSet) super.clone();
newSet.map = (HashMap) map.clone();
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
}
特點(diǎn):
LinkedHashSet是具有可預(yù)知迭代順序的Set接口的哈希表和鏈接列表實(shí)現(xiàn)。此實(shí)現(xiàn)與HashSet的不同之處在于,后者維護(hù)著一個(gè)運(yùn)行于所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序,該迭代順序可為插入順序或是訪問(wèn)順序。
注意,此實(shí)現(xiàn)不是同步的。如果多個(gè)線程同時(shí)訪問(wèn)鏈接的哈希Set,而其中至少一個(gè)線程修改了該Set,則它必須保持外部同步。
對(duì)于LinkedHashSet而言,它繼承與HashSet、又基于LinkedHashMap來(lái)實(shí)現(xiàn)的。
LinkedHashSet底層使用LinkedHashMap來(lái)保存所有元素,它繼承與HashSet,其所有的方法操作上又與HashSet相同,因此LinkedHashSet 的實(shí)現(xiàn)上非常簡(jiǎn)單,只提供了四個(gè)構(gòu)造方法,并通過(guò)傳遞一個(gè)標(biāo)識(shí)參數(shù),調(diào)用父類的構(gòu)造器,底層構(gòu)造一個(gè)LinkedHashMap來(lái)實(shí)現(xiàn),在相關(guān)操作上與父類HashSet的操作相同,直接調(diào)用父類HashSet的方法即可。
LinkedHashSet集合同樣是根據(jù)元素的hashCode值來(lái)決定元素的存儲(chǔ)位置,但是它同時(shí)使用鏈表維護(hù)元素的次序。這樣使得元素看起來(lái)像是以插入順序保存的,也就是說(shuō),當(dāng)遍歷該集合時(shí)候,LinkedHashSet將會(huì)以元素的添加順序訪問(wèn)集合的元素。
LinkedHashSet在迭代訪問(wèn)Set中的全部元素時(shí),性能比HashSet好,但是插入時(shí)性能稍微遜色于HashSet。
TreeSet存儲(chǔ)對(duì)象的時(shí)候, 可以排序, 但是需要指定排序的算法
Integer能排序(有默認(rèn)順序), String能排序(有默認(rèn)順序), 自定義的類存儲(chǔ)的時(shí)候出現(xiàn)異常(沒(méi)有順序)
如果想把自定義類的對(duì)象存入TreeSet進(jìn)行排序, 那么必須實(shí)現(xiàn)Comparable接口
在類上implement Comparable
重寫compareTo()方法
在方法內(nèi)定義比較算法, 根據(jù)大小關(guān)系, 返回正數(shù)負(fù)數(shù)或零
在使用TreeSet存儲(chǔ)對(duì)象的時(shí)候, add()方法內(nèi)部就會(huì)自動(dòng)調(diào)用compareTo()方法進(jìn)行比較, 根據(jù)比較結(jié)果使用二叉樹形式進(jìn)行存儲(chǔ)
public class TestIndexEntity implements Comparable{
private Integer id;
private String name;
private String desp;
private String content;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesp() {
return desp;
}
public void setDesp(String desp) {
this.desp = desp;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public int compareTo(Object o) {
TestIndexEntity entity = (TestIndexEntity)o;
int result = id < entity.id ? -1 : (id == entity.id ? 0 : 1);
return result;
}
}