四,Java集合類(2)——Set介面及其實現類
1,Set介面及其實現類
Set集合與Collection基本相同,沒有提供任何額外的方法。實際上Set就是Collection,只是行為略有不同。Set集合不允許包含相同的元素,如果試圖把兩個相同的元素加入同一個Set集合中,新增操作失敗,add()方法返回false,且新元素不會被加入。
1.2,HashSet類
HashSet按Hash演算法來儲存集合中的元素。HashSet有以下特點:
- 不能保證元素的排列順序,輸入順序和輸出順序可能不同。
- HashSet不是同步的,若有兩個以上的執行緒修改集合時候,必須程式碼保證同步。
- 集合元素可以為null。
如果HashSet中要存放類物件,則該物件需要重寫equals()和hashCode()方法。規則是若equals()返回的值是true,則這兩個物件的hashCode值也應該是相同的。
- equals返回的是true,hashCode返回的是兩個不同的值,則HashSet會將相同的數值存放在不同的位置,這樣就和Set存放不相同的數值的規則起衝突,不可以採用。
- equals返回的是true,hashCode返回的是兩個相同的值,則HashSet會將相同的數值在同一個位置上以連結串列的形式儲存。
package com.practice.collection; import java.util.HashSet; class A { @Override public boolean equals(Object arg0) { // TODO Auto-generated method stub return true; } } class B{ @Override public int hashCode() { // TODO Auto-generated method stub return 1; } } class C{ @Override public int hashCode() { // TODO Auto-generated method stub return 2; } @Override public boolean equals(Object obj) { // TODO Auto-generated method stub return true; } } public class HashSetTest { public static void main(String[] args) { HashSet books = new HashSet(); books.add(new A()); books.add(new A()); books.add(new B()); books.add(new B()); books.add(new C()); books.add(new C()); System.out.println(books); } }
1.3,LinkedHashSet類
LindedHahSet集合也是根據元素的hashCode值來決定元素的儲存位置,但它是使用連結串列的形式維護元素的次序。當遍歷LinkedHashSet集合裡的元素時,LinkedHashSet會按元素的新增順序來訪問集合裡的元素。LinkedHashSet需要維護元素的插入順序,因此效能略低於HashSet的效能。
package com.practice.collection; import java.util.LinkedHashSet; public class LinkedHashSetTest { public static void main(String[] args) { LinkedHashSet linkedHashSet = new LinkedHashSet(); linkedHashSet.add("Java從入門到出門"); linkedHashSet.add("PHP從入門到放棄"); linkedHashSet.add("Spring從入門到沒門"); linkedHashSet.add("Hibernate從入門到精通"); System.out.println(linkedHashSet); } }
1.4,TreeSet類
TreeSet可以確保集合元素處於排序狀態,這種排序狀態是根據元素的大小來排序的,並不是根據元素的插入順序來進行排序的。
package com.practice.collection; import java.util.TreeSet; public class TreeSetTest { public static void main(String[] args) { TreeSet treeSet = new TreeSet(); treeSet.add(1); treeSet.add(4); treeSet.add(5); treeSet.add(2); treeSet.add(3); System.out.println(treeSet); /*輸出集合中第一個元素*/ System.out.println(treeSet.first()); /*輸出集合中最後一個元素*/ System.out.println(treeSet.last()); /*輸出大於2,小於4的子集*/ System.out.println(treeSet.subSet(2, 4)); /*輸出大於2的子集,如果集合中有2,則還會輸出2*/ System.out.println(treeSet.tailSet(2)); /*輸出小於3的子集,不包括3*/ System.out.println(treeSet.headSet(3)); } }
1.5,EnumSet類
EnumSet是一個專門為列舉類設計的集合類,該集合中的元素都必須是指定列舉型別的列舉值,該列舉型別在建立EnumSet是顯示或隱式地指定。EnumSet的集合元素也是有序的,EnumSet以列舉值在Enum類內的定義順序來決定集合元素的順序。同時該集合不允許加入null元素,如果試圖加入null元素,EnumSet將會丟擲空指標異常。
package com.practice.collection; import java.util.EnumSet; enum Season{ SPRING,SUMMER,FALL,WINTER } public class EnumSetTest { public static void main(String[] args) { /*建立一個包含指定列舉類裡所有列舉值的EnumSet集合*/ EnumSet enumSet = EnumSet.allOf(Season.class); System.out.println(enumSet); /*建立一個元素型別為指定列舉型別的空的EnumSet集合*/ EnumSet enumSet2 = EnumSet.noneOf(Season.class); System.out.println(enumSet2); enumSet2.add(Season.WINTER); enumSet2.add(Season.SPRING); System.out.println(enumSet2); /*建立一個包含一個或多個列舉值的EnumSet集合,傳入的多個列舉值必須屬於同一個列舉類*/ EnumSet enumSet3 = EnumSet.of(Season.FALL, Season.WINTER, Season.SPRING); System.out.println(enumSet3); /*建立一個包含從from列舉值到to列舉值範圍內所有列舉值的EnumSet集合*/ EnumSet enumSet4 = EnumSet.range(Season.SPRING, Season.WINTER); System.out.println(enumSet4); /*建立一個其元素型別與指定EnumSet裡元素型別相同的的EnumSet集合 *新EnumSet集合包含原來EnumSet集合所不包含的,此列舉類剩下的列舉值 */ EnumSet enumSet5 = EnumSet.complementOf(enumSet4); System.out.println(enumSet5); } }
2,Set實現類效能分析
HashSet和TreeSet是Set介面的典型實現。對於HashSet和TreeSet如何選擇?
HashSet的效能總是比TreeSet好,特別是最常用的新增,查詢元素等操作。TreeSet需要額外的紅黑樹演算法來維護集合元素的次序。只有當需要一個保持排序的Set時候,才應該使用TreeSet。否則都應該使用HashSet。
LinkedHashSet是HashSet的子類,在正常的插入,刪除操作,LinkedHashSet比HashSet要略微慢一點,因為LinkedHashSet需要額外的維護自己的連結串列,也正是因為存在連結串列,遍歷LinkedHashSet相比較於HashSet要快點。
與其他三個相比較而言,EnumSet是效能相對比較好的。但是這個類只能使用同一個列舉類作為集合元素。
Set的三個實現類HashSet,TreeSet,EnumSet都是非執行緒安全的,所以在多個執行緒對集合訪問修改時候要保證集合的同步性。通常可以通過Collections工具類的synchronizedSortedSet方法來包裝該Set集合。該操作最好在建立時進行,以防止對Set集合的意外非同步訪問
SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));