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());
}
}
}