Set接口
如果有人告訴你Set是無序的,那你可以直接回懟他這是錯的,說法不嚴謹。
Set接口的實現類(都不能放重複值)
1.HashSet(無序)
2.LinkedHashSet(有序)
3.TreeSet(有序)
沒有ArraySet,這是因爲Array是連續的,Set是不連續的;
-
Set與List的相同點,也是Collection的子接口,也是容器
-
Set才叫真正意義上的集合,List叫做列表
-
集合與列表的區別:
列表是一條一條記錄的,而集合是圍在一起的
比如,有五個人,他們整整齊齊做一列就是列表,要是圍一堆坐着就是集合,不知道誰是頭,誰是尾
Set集合是沒有腳標的,所以Set裏面也沒有get方法,List有腳標,所以可以有get方法,List和Set是兄弟關係,這也正是Collection接口裏沒有get方法的原因。
-
集合中不能放重複的對象,這是因爲他沒有腳標。所以Set集合可用來去重
-
Set有點像水壺,茶壺裏煮餃子,倒不出來。要是想從Set裏拿出來,則必須把所有的值都拿出來
HashSet是無序的,注意是HashSet不是Set
forezch在底層使用迭代器實現的
如果一個類沒有迭代器,則它不能使用foreach循環
iterator.remove();不能連着使用
-
怎麼解釋hashset是無序的,怎麼解釋set不能放重複元素?
因爲hashSet的底層是按照hash算法排列得到的數列,他是一個不可逆的算法。每個對象都有一個hashcode,hash算法通過hashcode來排數據,所以hashset無序。
HashSet底層由HashMap實現,插入的元素被當做是HashMap的key,根據hashCode值來確定集合中的位置,在向HashMap中添加元素時,先判斷key的hashCode值是否相同,如果相同,則調用equals()、==進行判斷,若相同則覆蓋原有元素;如果不同,則直接向Map中添加元素;
set的兩個主要實現類,TreeSet和HashSet,底層存儲結構都是用的map,而且是將set需要存儲的值放在map的key裏的,value是一個空的object對象。
-
那有沒有有序的set呢
有,LinkedHashSet, 往裏放的什麼順序,打印出來的就是什麼順序,以鏈表的形式存當前的元素,只是鏈表位置被hash了,但是它沒有下標
還有一個有序的set,TreeSet。按comparable升序排列,它的底層實現是二叉樹
TreeSet有個約束,往它裏面放到內容必須實現comparable接口
一、HashSet
在向HashMap中添加元素時,先判斷key的hashCode值是否相同,如果相同,則調用equals()、==進行判斷,若相同則覆蓋原有元素;如果不同,則直接向Map中添加元素;
public class Main {
public static void main(String[] args) {
Set<String> sets = new HashSet<>();
sets.add("zhang");
sets.add("ao");
sets.add("qi");
sets.add("zhang");
sets.add("san");
Iterator<String> iterator = sets.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
} //輸出:san qi zhang ao //無序的且不重複
sets.remove("ao");//刪除元素
sets.clear(); //清空容器
}
}
二、LinkedHashSet(直接父類是 HashSet)
特點:存取有序,存儲的元素不能重複。
Set<String> sets = new LinkedHashSet<>();
sets.add("a");
sets.add("a");
sets.add("a");
sets.add("b");
sets.add("b");
sets.add("c");
sets.add("d");
for (String str:sets
) {
System.out.println(str);
}
//輸出a b c d
三、TreeSet( 底層結構爲紅黑樹 )
與HashSet不同的是,TreeSet具有排序功能,分爲自然排序(123456)和自定義排序兩類,默認是自然排序;在程序中,我們可以按照任意順序將元素插入到集合中,等到遍歷時TreeSet會按照一定順序輸出–倒序或者升序;
方式一: 讓元素所在的類實現Comparable接口,並重寫CompareTo() 方法,並根據CompareTo()的返回值來進行添加元素
- 返回正數:往二叉樹的右邊添加
- 返回負數:往二叉樹的左邊添加
- 返回 0 : 說明重複,不添加
方式二: 使用TreeSet的有參構造方法創建TreeSet對象的時候, 傳入一個比較器 Comparator 進去, TreeSet在添加元素的時候, 根據比較器的compare()方法的返回值來添加元素。
- 返回正數:往二叉樹的右邊添加
- 返回負數:往二叉樹的左邊添加
- 返回 0 : 說明重複,不添加
TreeSet存儲元素對元素進行排序的源碼解析
TreeSet在存儲元素的時候會首先去判斷是否有比較器存在(也就是判斷比較器是否爲null),如果存在:就會讓比較器去調用compare(T t1, T t2)方法,去依次比較即將存入的值和已經存入TreeSet集合的值,如果返回正數:往二叉樹右側放;如果返回負數:往二叉樹左側放;如果返回 0 :不添加。如果不存在:底層就會把即將存入的元素自動提升爲Comparable類型的對象(所以如果沒有比較器的情況下,元素所在的類沒有實現Comparable接口,在做自動提升類型的時候就會報類型轉換錯誤),並讓該對象調用CompareTo(T t)方法,和已經存入TreeSet集合的元素依次比較,如果返回正數:往二叉樹右側放;如果返回負數:往二叉樹左側放;如果返回 0 :不添加。所以,如果兩種方式同時使用,底層會優先使用方式二(比較器的方式)。
學習參考:
https://blog.csdn.net/Qingai521/article/details/87968134
https://www.baidu.com/link?url=o4mGbw9BArl9kO8SxYj_9jYdwjO5FsfggK8FpB6CCxsj1SxlIhSRsx7_3mAu_2F3&wd=&eqid=a848f8fb0007e998000000035dfaf2c7