Set接口
無序,不可重複
具體實作類:HashSet LinkedHashSet TreeSet
set接口的架構結構
HashSet:作為set接口的主要實作類; 線程不安全,可以存儲null值
LinkedHashSet:作為HashSet的子類:周遊其内部資料時,可以按照添加的順序周遊
TreeSet:可以按照添加對象的指定屬性,進行排序
- set接口中沒有額外定義新的方法,使用的都是collection中聲明過的方法。
- 要求:向set中添加的資料,其所在類一定要重寫hashCode()和equals(),重寫的兩個方法盡可能保持一緻性,即“相等的對象有相等的散列碼”
以HashSet為例說明:
- 無序性 不等于 随機性;存儲的資料在底層數組中并非按照數組索引的順序添加,而是根據資料的哈希值進行添加
- 不可重複性:保證添加的元素按照equals()判斷時,不能傳回true。即相同的元素隻能添加一個。
package com.collection.set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Demo00 {
public static void main(String[] args) {
test();
}
private static void test() {
Set set = new HashSet();
set.add(123);
set.add(3);
set.add(456);
set.add(45);
set.add("cc");
set.add("aa");
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
// 列印的順訊并不是添加的順序
}
}
}
添加元素的過程
以HashSet為例
我們向HashSet中添加元素a,首先調用元素a所在類的hashCode()方法,計算元素a的哈希值,此哈希值接着通過某種算法計算出在HashSet底層數組中的存放位置(即為:索引位置),判斷此位置上是否已經有元素:
如果此位置沒有其他元素,則元素a添加成功–情況1
如果此位置有其他元素b(或以連結清單形式存在的多個元素),則比較元素a與元素b的hash值:
如果hash值不相同,則元素a添加成功–情況2
如果hash值相同,進而需要調用元素a所在類的equals()方法:
equals() 傳回true,元素a添加失敗
equals() 傳回false,元素a添加成功–情況3
對于添加成功的情況2和情況3而言:元素a與已經存在指定索引位置上資料以連結清單的方式存儲。
Jdk7:元素a放到數組中,指向原來的元素
Jdk8: 原來的元素在數組中,指向元素a
底層是數組結構+連結清單結構,初始容量為16。當如果使用率超過0.75,就會擴大容量為原來的2倍
LinkedHashSet的使用
LinkedHashSet作為HashSet的子類,在添加資料的同時,每個資料還維護了兩個引用,記錄此資料前一個資料和後一個資料
優點:對于頻繁的周遊操作,LinkedHashSet效率高于HashSet
// linkedhashset
public static void test2(){
Set set2 = new LinkedHashSet();
set2.add(123);
set2.add(3);
set2.add(456);
set2.add(45);
set2.add("cc");
set2.add("aa");
Iterator iterator = set2.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
// 列印順序是添加的順序
}
}
TreeSet的使用
- 向TreeSet中添加的資料,要求是相同類的對象
- 兩種排序方式:自然排序(實作comparable接口) 和 定制排序(comparator接口)
- 自然排序中,比較兩個對象是否相同的标準為:compareTo()傳回0,不再是equals(). 是以不能放相同的資料
- 定制排序中,自然排序中,比較兩個對象是否相同的标準為:compare()傳回0,不再是equals(). 是以不能放相同的資料
public static void test3() {
TreeSet set3 = new TreeSet();
//integer
// set3.add(123);
// set3.add(3);
// set3.add(456);
// set3.add(45);
// set3.add(-3);
//string
set3.add("cc");
set3.add("aa"); //不能添加不同類的對象
set3.add("dd");
set3.add("ee");
Iterator iterator = set3.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
// print按照從小到大的順序
}
}
private static void test4() {
// 按照age排序
Comparator com = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof User && o2 instanceof User){
User u1 = (User)o1;
User u2 = (User)o2;
return Integer.compare(u1.getAge(),u2.getAge());
}else{
throw new RuntimeException("輸入的資料類型不比對")
}
}
};
TreeSet set4 = new TreeSet(com); // 有參,按照參數的方式排序
// 不寫參數 則按照自然排序;寫了參數,定制排序
set4.add(new User("tom",12));
set4.add(new User("joe",24));
set4.add(new User("amy",45));
}