1. 程式人生 > >JavaSE集合

JavaSE集合

Set介面是Collection的子介面,set介面沒有提供額外的方法。Set體系中的類或介面一般都包含"Set"字眼。

Set 集合不允許包含相同的元素,如果試把兩個相同的元素加入同一個 Set 集合中,則新增操作失敗。

Set 判斷兩個物件是否相同不是使用 == 運算子,而是根據 equals 方法

map中的所有key,即為一個set;所有value,即為一個collection。

【1】Set實現類之一–HashSet

HashSet 是 Set 介面的典型實現,大多數時候使用 Set 集合時都使用這個實現類。

HashSet 按 Hash 演算法來儲存集合中的元素,因此具有很好的存取和查詢效能。

HashSet 具有以下特點:

不能保證元素的排列順序
HashSet 不是執行緒安全的
集合元素可以是 null

當向 HashSet 集合中存入一個元素時,HashSet 會呼叫該物件的 hashCode() 方法來得到該物件的 hashCode 值,然後根據 hashCode 值決定該物件在 HashSet 中的儲存位置。

HashSet 集合判斷兩個元素相等的標準:兩個物件通過 hashCode() 方法比較相等,並且兩個物件的 equals() 方法返回值也相等。

【2】hashCode() 方法

如果兩個元素的 equals() 方法返回 true,但它們的 hashCode() 返回值不相等,hashSet 將會把它們儲存在不同的位置,但依然可以新增成功。

對於存放在Set容器中的物件,對應的類一定要重寫equals()和hashCode(Object obj)方法,以實現物件相等規則。

重寫 hashCode() 方法的基本原則:

  • 在程式執行時,同一個物件多次呼叫 hashCode() 方法應該返回相同的值;

  • 當兩個物件的 equals() 方法比較返回 true 時,這兩個物件的 hashCode() 方法的返回值也應相等;

  • 物件中用作 equals() 方法比較的 Field,都應該用來計算 hashCode 值。

【3】LinkedHashSet

LinkedHashSet 是 HashSet 的子類。LinkedHashSet 根據元素的 hashCode 值來決定元素的儲存位置,但它同時使用連結串列維護元素的次序,這使得元素看起來是以插入順序儲存的。

LinkedHashSet插入效能略低於 HashSet,但在迭代訪問 Set 裡的全部元素時有很好的效能。

LinkedHashSet 同樣不允許集合元素重複。

【4】TreeSet

TreeSet 是 SortedSet 介面的實現類,TreeSet 可以確保集合元素處於排序狀態。

TreeSet 是一個有序的集合,它的作用是提供有序的Set集合。它繼承於AbstractSet抽象類,實現了NavigableSet<E>,Cloneable,java.io.Serializable介面

其主要方法如下所示:

Comparator comparator()
Object first()
Object last()
Object lower(Object e)
Object higher(Object e)
SortedSet subSet(fromElement, toElement)
SortedSet headSet(toElement)
SortedSet tailSet(fromElement)

TreeSet 兩種排序方法:自然排序和定製排序。預設情況下,TreeSet 採用自然排序。

① 自然排序

TreeSet 會呼叫集合元素的 compareTo(Object obj) 方法來比較元素之間的大小關係,然後將集合元素按升序排列。

這也就意味著,如果試圖把一個物件新增到 TreeSet 時,則該物件的類必須實現 Comparable 介面。

實現 Comparable介面 的類必須實現 compareTo(Object obj) 方法,兩個物件即通過 compareTo(Object obj) 方法的返回值來比較大小。

java.lang.Comparable<T>介面原始碼如下:

public interface Comparable<T> {
    public int compareTo(T o);
    //即a.compare(b); a b是同一個類的兩個不同例項
}

Comparable 的典型實現:

  • BigDecimal、BigInteger 以及所有的數值型對應的包裝類:按它們對應的數值大小進行比較
  • Character:按字元的 unicode值來進行比較
  • Boolean:true 對應的包裝類例項大於 false 對應的包裝類例項
  • String:按字串中字元的 unicode 值進行比較
  • Date、Time:後邊的時間、日期比前面的時間、日期大

向 TreeSet 中新增元素時,只有第一個元素無須比較compareTo()方法,後面新增的所有元素都會呼叫compareTo()方法進行比較。

因為只有相同類的兩個例項才會比較大小,所以向 TreeSet 中新增的應該是同一個類的物件。

對於 TreeSet 集合而言,它判斷兩個物件是否相等的唯一標準是:兩個物件通過 compareTo(Object obj) 方法比較返回值。

當需要把一個物件放入 TreeSet 中,重寫該物件對應的 equals() 方法時,應保證該方法與 compareTo(Object obj) 方法有一致的結果。

如果兩個物件通過 equals() 方法比較返回 true,則通過 compareTo(Object obj) 方法比較應返回 0。

程式碼例項如下:

public class TreeSetDemo {
	public static void main(String[] args) {
		// 建立集合物件
		// 自然順序進行排序
		TreeSet<Integer> ts = new TreeSet<Integer>();
 
		// 建立元素並新增
		// 20,18,23,22,17,24,19,18,24
		ts.add(20);
		ts.add(18);
		ts.add(23);
		ts.add(22);
		ts.add(17);
		ts.add(24);
		ts.add(19);
		ts.add(18);
		ts.add(24);
 
		// 遍歷
		for (Integer i : ts) {
			System.out.println(i);
		}
	}
}

② 定製排序

TreeSet的自然排序是根據集合元素的compareTo方法,進行元素升序排列。

如果需要定製排序,比如降序排列,可通過java.util.Comparator<T>介面的幫助,重寫compare(T o1,T o2)方法。

利用int compare(T o1,T o2)方法,比較o1和o2的大小:如果方法返回正整數,則表示o1大於o2;如果返回0,表示相等;返回負整數,表示o1小於o2。

要實現定製排序,需要將實現Comparator介面的例項作為形參傳遞給TreeSet的構造器。

此時,仍然只能向TreeSet中新增型別相同的物件,否則發生ClassCastException異常。

使用定製排序判斷兩個元素相等的標準是:通過Comparator比較兩個元素返回了0。

例項如下:


public class TreeSetDemo {
        public static void main(String[] args) {
                // 如果一個方法的引數是介面,那麼真正要的是介面的實現類的物件
		// 而匿名內部類就可以實現這個東西
		TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
			@Override
			public int compare(Student s1, Student s2) {
				// 姓名長度
				int num = s1.getName().length() - s2.getName().length();
				// 姓名內容
				int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
						: num;
				// 年齡
				int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
				return num3;
			}
		});
 
		// 建立元素
		Student s1 = new Student("linqingxia", 27);
		Student s2 = new Student("zhangguorong", 29);
		Student s3 = new Student("wanglihong", 23);
		// 新增元素
		ts.add(s1);
		ts.add(s2);
		ts.add(s3);
		// 遍歷
		for (Student s : ts) {
			System.out.println(s.getName() + "---" + s.getAge());
		}
	}
}