Set:無順序,不包含重復的元素
HashSet:為快速查找設計的Set。存入HashSet的對象必須定義hashCode()。
TreeSet: 保存次序的Set, 底層為樹結構。使用它可以從Set中提取有序的序列。
LinkedHashSet:具有HashSet的查詢速度,且內部使用鏈表維護元素的順序(插入的次序)。於是在使用迭代器遍歷Set時,結果會按元素插入的次序顯示。
HashSet:
import java.util.HashSet; import java.util.Iterator; public class Main { public static void main(String[] args) { HashSet set = new HashSet(); //分別向books集合中添加兩個A對象,兩個B對象,兩個C對象 set.add(new A()); set.add(new A()); set.add(new B()); set.add(new B()); set.add(new C()); set.add(new C()); System.out.println(set); System.out.println(set.size()); for(Iterator iter = set.iterator(); iter.hasNext();){ Object value = iter.next(); System.out.println(value); } } } //類A的equals方法總是返回true,但沒有重寫其hashCode()方法。不能保證當前對象是HashSet中的唯一對象 class A { public boolean equals(Object obj) { return true; } } //類B的hashCode()方法總是返回1,但沒有重寫其equals()方法。不能保證當前對象是HashSet中的唯一對象 class B { public int hashCode() { return 1; } } //類C的hashCode()方法總是返回2,且有重寫其equals()方法 class C { public int hashCode() { return 2; } public boolean equals(Object obj) { return true; } }
Result:

[com.qhong.B@1, com.qhong.B@1, com.qhong.C@2, com.qhong.A@677327b6, com.qhong.A@1540e19d] 5 com.qhong.B@1 com.qhong.B@1 com.qhong.C@2 com.qhong.A@677327b6 com.qhong.A@1540e19d
B類的hashcode值一樣,但是沒有定義equals,所以存儲了兩個對象,但是對象因為hashcode一樣,存儲位置也一樣,兩個對象按鏈表方式存儲。
C類中hashcode值一樣,equals也一樣,所以只能存儲一個值。
A類中沒有定義hashcode,所以存儲位置不一樣,這里還沒有進行equals對比,一樣存儲兩個對象。
LinkedHashSet
import java.util.Iterator; import java.util.LinkedHashSet; public class Main { public static void main(String[] args) { LinkedHashSet books = new LinkedHashSet(); books.add("Java1"); books.add("Java2"); System.out.println(books); //刪除 Java books.remove("Java1"); //重新添加 Java books.add("Java1"); System.out.println(books); for(Iterator iter = books.iterator(); iter.hasNext();){ Object value = iter.next(); System.out.println(value); } } }
Result:

[Java1, Java2]
[Java2, Java1]
Java2
Java1
元素的順序總是與添加順序一致,LinkedHashSetTest是HashSet的子類,因此它不允許集合元素重復.
TreeSet:
import java.util.TreeSet; public class Main { public static void main(String[] args) { TreeSet nums = new TreeSet(); //向TreeSet中添加四個Integer對象 nums.add(5); nums.add(2); nums.add(10); nums.add(-9); //輸出集合元素,看到集合元素已經處於排序狀態 System.out.println(nums); //輸出集合里的第一個元素 System.out.println(nums.first()); //輸出集合里的最后一個元素 System.out.println(nums.last()); //返回小於4的子集,不包含4 System.out.println(nums.headSet(4)); //返回大於5的子集,如果Set中包含5,子集中還包含5 System.out.println(nums.tailSet(5)); //返回大於等於-3,小於4的子集。 System.out.println(nums.subSet(-3 , 4)); } }
Result:

[-9, 2, 5, 10] -9 10 [-9, 2] [5, 10] [2]
與HashSet集合采用hash算法來決定元素的存儲位置不同,TreeSet采用紅黑樹的數據結構來存儲集合元素。
TreeSet支持兩種排序方式: 自然排序、定制排序
TreeSet會調用集合元素的compareTo(Object obj)方法來比較元素之間的大小關系,然后將集合元素按升序排序,即自然排序。
通過ComparaTor接口可以實現定制排序。
import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; public class Main { public static void main(String[] args) { TreeSet ts = new TreeSet(new Comparator() { //根據M對象的age屬性來決定大小 public int compare(Object o1, Object o2) { M m1 = (M)o1; M m2 = (M)o2; return m1.age > m2.age ? -1 : m1.age < m2.age ? 1 : 0; } }); ts.add(new M(5)); ts.add(new M(-3)); ts.add(new M(9)); System.out.println(ts); for(Iterator iter = ts.iterator(); iter.hasNext();){ Object value = iter.next(); System.out.println(value); } } } class M { int age; public M(int age) { this.age = age; } public String toString() { return "M[age:" + age + "]"; } }
Result:

[M[age:9], M[age:5], M[age:-3]] M[age:9] M[age:5] M[age:-3]
EnumSet:
import java.util.EnumSet; public class Main { public static void main(String[] args) { //創建一個EnumSet集合,集合元素就是Season枚舉類的全部枚舉值 EnumSet es1 = EnumSet.allOf(Season.class); //輸出[SPRING,SUMMER,FALL,WINTER] System.out.println(es1); //創建一個EnumSet空集合,指定其集合元素是Season類的枚舉值。 EnumSet es2 = EnumSet.noneOf(Season.class); //輸出[] System.out.println(es2); //手動添加兩個元素 es2.add(Season.WINTER); es2.add(Season.SPRING); //輸出[SPRING,WINTER] System.out.println(es2); //以指定枚舉值創建EnumSet集合 EnumSet es3 = EnumSet.of(Season.SUMMER , Season.WINTER); //輸出[SUMMER,WINTER] System.out.println(es3); EnumSet es4 = EnumSet.range(Season.SUMMER , Season.WINTER); //輸出[SUMMER,FALL,WINTER] System.out.println(es4); //新創建的EnumSet集合的元素和es4集合的元素有相同類型, //es5的集合元素 + es4集合元素 = Season枚舉類的全部枚舉值 EnumSet es5 = EnumSet.complementOf(es4); //輸出[SPRING] System.out.println(es5); } } enum Season { SPRING,SUMMER,FALL,WINTER }
Result:

[SPRING, SUMMER, FALL, WINTER]
[]
[SPRING, WINTER]
[SUMMER, WINTER]
[SUMMER, FALL, WINTER]
[SPRING]
Set集合類應用場景:
1) HashSet的性能總是比TreeSet好(特別是最常用的添加、查詢元素等操作),因為TreeSet需要額外的紅黑樹算法來維護集合元素的次序。只有當需要一個保持排序的Set時,才應該使用TreeSet,否則都應該使用HashSet 2) 對於普通的插入、刪除操作,LinkedHashSet比HashSet要略慢一點,這是由維護鏈表所帶來的開銷造成的。不過,因為有了鏈表的存在,遍歷LinkedHashSet會更快 3) EnumSet是所有Set實現類中性能最好的,但它只能保存同一個枚舉類的枚舉值作為集合元素 4) HashSet、TreeSet、EnumSet都是"線程不安全"的,通常可以通過Collections工具類的synchronizedSortedSet方法來"包裝"該Set集合。 SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));