一、Set接口的特點
一個不包含重復元素的collection。更確切地講,Set不包含滿足e1.equals(e2)的元素對 e1和e2,并且最多包含一個null元素。
Set集合由Set接口和Set接口的實現類組成,Set接口繼承了Collection接口,因此包含了Collection接口的所有方法。其主要實現類有HashSet和TreeSet,在HashSet的基礎上又延伸出了LinkedHashSet。
HashSet和TreeSet的不同就在于如何判斷兩個數是否相同的方法上。
1.HashSet判斷兩個對象是否相同的方法時繼承自Object類的equals方法
(public boolean equals(Object o)方法只可以比較是否相等,相等返回true,反之返回false)。
2.TreeSet判斷兩個對象是否相同的方法則是Comparable接口中的compareTo()方法
(public void int compareTo(Object o)方法不僅可以比較是否相等,還可以比較大小,如果相等返回0,調用者大于參數則返回正數,否則返回負數)
所以可以得到添加到TreeSet中的對象必須實現Comparable接口。同時如果使用HashSet則最好重寫equals()方法。
二、HashSet
HashSet實現了Set接口,基于HashMap進行存儲。遍歷時不保證順序,并不保證下次遍歷的順序和之前一樣。HashSet中允許null值。
進入到HashSet源碼中我們發現,所有數據存儲在
private transient HashMap<E, Object> map;
private static final Object PRESENT = new Object();
意思就是HashSet的集合其實就是HashMap的key的集合,然后HashMap的val默認都是PRESENT。HashMap的定義即是key不重復的集合。使用HashMap實現,這樣HashSet就不需要再實現一遍。
所以所有的add,remove等操作其實都是HashMap的add、remove操作。遍歷操作其實就是HashMap的keySet的遍歷。
1.HashSet底層實際上是一個HashMap,HashMap底層采用了哈希表數據結構。
2.哈希表又叫散列表,哈希表底層是一個數組,這個數組中每一個元素是一個單向鏈表,每個單向鏈表都有一個獨一無二的hash值,代表數組的下表。在某個單向鏈表中的每個節點上的hash值是相同的。hash值實際上是key調用hashCode方法,再通過“hash function”轉換成的值。
3.如何向哈希表中添加元素?
先調用存儲的key的hashCode方法,經過 某個算法得到hash值,如果這個哈希表中不存在這個hash值,則直接加入元素。如果該hash值已經存在,繼續調用key之間的equals方法,如果equals方法返回false,則將該元素添加。如果equals方法返回true,則放棄添加該元素 ,即元素重復。HashMap和HashSet的初始化容量是16,默認加載因子是0.75。
另外,HashSet完全繼承了Set或者Collection里的方法實現add、addAll、clear、isEmpty、size、contains、iterator、remove等
三、TreeSet
TreeSet類型是J2SE中唯一可實現自動排序的類型
? TreeSet是SortedSet接口的唯一實現類,TreeSet可以確保集合元素處于排序狀態。TreeSet支持兩種排序方式,自然排序 和定制排序,其中自然排序為默認的排序方式。向 TreeSet中加入的應該是同一個類的對象。
? TreeSet判斷兩個對象不相等的方式是兩個對象通過equals方法返回false,或者通過CompareTo方法比較沒有返回0
TreeSet集合:可以對Set集合中的元素進行排序。是不同步的。
但是TreeSet集合的存儲是有序的,即:存儲到集合中的元素是按自然順序存儲的。
判斷元素唯一性的方式:
根據比較方法的返回值來判斷。是0(零)就存入集合,不是0就不存。因為Set集合是不能有重復的元素,無序。
TreeSet要注意的事項:
1.往TreeSet里面添加元素時候,如果元素本具備自然順序特性,那么就按照元素的自然順序排序存儲.
2.往TreSet里面添加元素時候,如果元素不具備自然順序特性,那么該元素就必須要實現Comparable接口,把元素的比較規則定義在compareTo(T o)方法中
3.如果比較元素的時候,compareTo返回的是0,那么該元素被視為重復元素,不允許添加 (注意:TreeSet與HashCode,equals沒有任何關系)
4.往TreeSet里面添加元素時候,如果元素本身不具備自然自然順序特性,而且元素所屬類也沒有實現Comparable接口,那么我們必須要在創建TreeSet的時候傳入一個比較器.
自定義比較器
自定一個比較器只需要實現接口 Comparator即可,把元素與元素之間的比較規則定義在compare方法內即可
自定義比較器的格式:
class 類名 implements Comparator<T>{}
(一)、自然排序
實現Comparable接口比較元素
自然排序使用要排序元素的CompareTo(Object obj)方法來比較元素之間大小關系,然后將元素按照升序排列。
Java提供了一個Comparable接口,該接口里定義了一個compareTo(Object obj)方法,該方法返回一個整數值,實現了該接口的對象就可以比較大小。
obj1.compareTo(obj2)方法如果返回0,則說明被比較的兩個對象相等,如果返回一個正數,則表明obj1大于obj2,如果是 負數,則表明obj1小于obj2。
如果我們將兩個對象的equals方法總是返回true,則這兩個對象的compareTo方法返回應該返回0
(二)定制排序
自定義比較器比較元素
自然排序是根據集合元素的大小,以升序排列,如果要定制排序,應該使用Comparator接口,實現 int **compare(To1,To2)**方法
(三)TreeSet總結:
1.特點
TreeSet是用來排序的,可以指定一個順序,對象存入之后會按照指定的順序排列
2.使用方式
(1)自然順序(Comparable)
TreeSet類的add()方法會把存入的對象提升為Comparable類型
調用對象的comparaTo()方法和集合中的對象比較
根據comparaTo()方法返回的結果進行存儲
(2)比較器順序
創建TreeSet的時候可以指定一個Comparator
如果傳入了Comparator的子類對象,那么TreeSet就會按照比較器的順序排序。
add()方法內部會自動調用Comparator接口中的compare()方法排序
調用的對象是compare方法的第一個參數,集合中的對象是compare方法的第二個參數
(3)兩種方式的區別
TreeSet構造函數什么都不傳,默認按照類中Comparable的順序(沒有就報錯ClassCastException)
TreeSet如果傳入Comparator,就有先按照Comparator
四、LinkedHashSet
(一)、LinkedHashSet概述
LinkedHashSet集合也是根據元素hashCode值來決定元素存儲位置,但它同時使用鏈表維護元素的次序,這樣使得元素看起來是以插入的順序保存的。也就是說,當遍歷LinkedHashSet集合里元素時,HashSet將會按元素的添加順序來訪問集合里的元素。
LinkedHashSet需要維護元素的插入順序,因此性能略低于HashSet的性能,但在迭代訪問Set里的全部元素時將有很好的性能,因為它以鏈表來維護內部順序。
(二)LinkedHashSet結論
輸出LinkedHashSet集合中的元素時,元素的順序總是和添加順序一致。