摘要:當(dāng)復(fù)制集合中的所有元素來創(chuàng)建新的集合時(shí),要求集合中的所有元素必須是同一個(gè)枚舉類的枚舉值各實(shí)現(xiàn)類的性能分析的性能總比好,特別是最常用的添加查詢元素等操作。因?yàn)樾枰~外的紅黑樹算法來維護(hù)集合元素的次序。在創(chuàng)建時(shí)進(jìn)行,以防對集合的意外非同步訪問
HashSet
大多時(shí)候使用Set集合時(shí)就是使用HashSet實(shí)現(xiàn)類。HashSet按Hash算法來存儲集合中的元素,因此具有很好的存取和查找性能
HashSet具有以下特點(diǎn)
不能保證元素的排列順序,順序可能與添加順序不同,順序也有可能發(fā)生變化
HashSet不是同步的,如果多個(gè)線程同時(shí)訪問一個(gè)HashSet,假設(shè)有兩個(gè)或兩個(gè)以上線程同時(shí)修改了HashSet集合時(shí),則必須通過代碼來保證其同步
集合元素值可以是null
HashSet會調(diào)用該對象的hashCode()方法來得到該對象的hashCode()值,然后根據(jù)該hashCode()值決定該對象在HashSet中的存儲位置;HashSet集合判斷兩個(gè)元素相等的標(biāo)準(zhǔn)是兩個(gè)對象通過equals()方法比較相等,并且兩個(gè)對象的hashCode()方法返回值也相等
hash(也被翻譯為哈希、散列)算法的功能:
它能保證快速查找被檢索的對象,hash算法的價(jià)值在于速度。當(dāng)需要查詢集合中某個(gè)元素時(shí),hash算法可以根據(jù)該元素的hashCode值計(jì)算出該元素的存儲位置,從而快速定位該元素。
為什么不直接使用數(shù)組、還需要使用HashSet?
因?yàn)閿?shù)組元素的索引是連續(xù)的,而且數(shù)組的長度是固定的、無法自由增加數(shù)組的長度。而HashSet采用每個(gè)元素的hashCode值來計(jì)算其存儲位置,從而可以自由增加HashSet的長度,并可以根據(jù)元素的HashCode值來訪問元素。因此,當(dāng)從HashSet中訪問元素時(shí),HashSet先計(jì)算該元素的hashCode值(調(diào)用該對象的hashCode()方法的返回值),然后直接到該hashCode值對應(yīng)的位置去取出該元素——這就是HashSet速度很快的原因
HashSet中每個(gè)能存儲元素的“槽位”(slot)通常稱為“桶”(bucket)
hashCode()方法的基本重寫規(guī)則
在程序運(yùn)行過程中,同一個(gè)對象多次調(diào)用hashCode()方法應(yīng)該返回相同的值
當(dāng)兩個(gè)對象通過equals()方法比較返回true時(shí),這兩個(gè)對象的hashCode()方法應(yīng)該返回相等的值
對象中用作equals()方法比較標(biāo)準(zhǔn)的實(shí)例變量,都應(yīng)該用于計(jì)算hashCode()值
hashCode()方法的基本重寫步驟
把對象內(nèi)每個(gè)有意義的實(shí)例變量(即每個(gè)參與equals()方法比較標(biāo)準(zhǔn)的實(shí)例變量)計(jì)算出一個(gè)Int類型的hashCode值
用第一步計(jì)算出來的多個(gè)hashCode值組合計(jì)算出一個(gè)hashCode值返回
LinkedHashSet類LinkedHashSet集合根據(jù)元素的hashCode值來決定元素的存儲位置,同時(shí)使用鏈表維護(hù)元素的次序,這樣使得元素看起來是以插入的順序保存的。當(dāng)遍歷LinkedHashSet集合里的元素時(shí),LinkedHashSet將會按元素的添加順序來訪問集合里的元素
LinkedHashSet需要維護(hù)元素的插入順序,因此性能略低于HashSet的性能,但在迭代訪問Set里的全部元素時(shí)將有很好的性能,因?yàn)樗枣湵韥砭S護(hù)內(nèi)部順序
雖然LinkedHashSet使用了鏈表記錄集合元素的添加順序,但LinkedHashSet依然是HashSet,因此不允許集合元素重復(fù)
TreeSet類TreeSet是SortedSet接口的實(shí)現(xiàn)類,可以確保集合元素處于排序狀態(tài)。根據(jù)元素實(shí)際值的大小進(jìn)行排序
TreeSet的額外方法
Comparator comparator():如果TreeSet采用了定制排序,則該方法返回定制排序所使用的Comparator;如果TreeSet采用了自然排序,則返回null
Object first():返回集合中的第一個(gè)元素
Object last():返回集合中的最后一個(gè)元素
Object lower(Object e):返回集合中位于指定元素之前的元素(即小于指定元素的最大元素,參考元素不需要是TreeSet集合里的元素)
Object higher(Object e):返回集合中位于指定元素之后的元素(即大于指定元素的最小元素,參考元素不需要是TreeSet集合里的元素)
SortedSet subSet(Object fromElement, Object toElement):返回此Set的子集,范圍從fromElement(包括)到toElement(不包括)
SortedSet headSet(Object toElement):返回此Set的子集,由小于toElement的元素組成
SortedSet tailSet(Object fromElement):返回此Set的子集,由大于或等于fromElement的元素組成
HashSet采用hash算法來決定元素的存儲位置,TreeSet采用紅黑樹的數(shù)據(jù)結(jié)構(gòu)來存儲集合元素。
TreeSet支持兩種排序方法。在默認(rèn)情況下,TreeSet采用自然排序
import java.util.*; public class TreeSetTest { public static void main(String[] args) { TreeSet nums = new TreeSet(); // 向TreeSet中添加四個(gè)Integer對象 nums.add(5); nums.add(2); nums.add(10); nums.add(-9); // 輸出集合元素,看到集合元素已經(jīng)處于排序狀態(tài) System.out.println(nums); // 輸出集合里的第一個(gè)元素 System.out.println(nums.first()); // 輸出-9 // 輸出集合里的最后一個(gè)元素 System.out.println(nums.last()); // 輸出10 // 返回小于4的子集,不包含4 System.out.println(nums.headSet(4)); // 輸出[-9, 2] // 返回大于5的子集,如果Set中包含5,子集中還包含5 System.out.println(nums.tailSet(5)); // 輸出 [5, 10] // 返回大于等于-3,小于4的子集。 System.out.println(nums.subSet(-3 , 4)); // 輸出[2] } }自然排序
TreeSet會調(diào)用集合元素的compareTo(Object obj)方法來比較元素之間的大小關(guān)系,然后將集合元素按升序排列,這種方式就是自然排列
compareTo(Object obj)方法返回一個(gè)整數(shù)值,實(shí)現(xiàn)該接口的類必須實(shí)現(xiàn)該方法,實(shí)現(xiàn)了該接口的類的對象就可以比較大小。當(dāng)一個(gè)對象調(diào)用該方法與另一個(gè)對象進(jìn)行比較時(shí),例如obj1.compareTo(obj2),如果該方法返回0,則表明這兩個(gè)對象相等;如果該方法返回一個(gè)正整數(shù),則表明obj1大于obj2;如果該方法返回一個(gè)負(fù)整數(shù),則表明obj1小于obj2
實(shí)現(xiàn)了Comparable接口的常用類
BigDecimal、BigInteger以及所有的數(shù)組型對應(yīng)的包裝類:按它們對應(yīng)的數(shù)組大小進(jìn)行比較
Character:按字符的UNICODE值進(jìn)行比較
Boolean:true對應(yīng)的包裝類實(shí)例大于false對應(yīng)的包裝類實(shí)例
String:按字符串中字符的UNICODE值進(jìn)行比較
Date、Time:后面的時(shí)間、日期比前面的時(shí)間、日期大
一個(gè)對象添加到TreeSet時(shí),則該對象的類必須實(shí)現(xiàn)Comparable接口,否則程序?qū)伋霎惓?/p>
import java.util.TreeSet; class Error{ } public class TreeSetErrorTest { public static void main(String[] args) { TreeSet treeSet = new TreeSet<>(); treeSet.add(new Error()); treeSet.add(new Error()); //① } }
添加第一個(gè)對象時(shí),TreeSet里沒有任何元素,所以不會出現(xiàn)任何問題;當(dāng)添加第二個(gè)Error對象時(shí),TreeSet就會調(diào)用該對象的compareTo(Object obj)方法與集合中的其他元素進(jìn)行比較——如果其對應(yīng)的類沒有實(shí)現(xiàn)Comparable接口,則會引發(fā)ClassCastException異常
向TreeSet集合中添加元素時(shí),只有第一個(gè)元素?zé)o須實(shí)現(xiàn)Comparable接口,后面添加的所有元素都必須實(shí)現(xiàn)Comparable接口
把一個(gè)對象添加到TreeSet集合時(shí),TreeSet會調(diào)用該對象的compareTo(Object obj)方法與集合中的其他元素進(jìn)行比較。向TreeSet中添加的應(yīng)該是同一個(gè)類的對象,否則也會引發(fā)ClassCastException異常
如果希望TreeSet能正常運(yùn)行,TreeSet只能添加同一種類型的對象
當(dāng)把一個(gè)對象加入TreeSet集合中時(shí),TreeSet調(diào)用該對象的compareTo(Object obj)方法與容器中的其他對象比較大小,然后根據(jù)紅黑樹結(jié)構(gòu)找到它的存儲位置。如果兩個(gè)對象通過compareTo(Object obj)方法比較相等,新對象將無法添加到TreeSet集合中
定制排序TreeSet的自然排序是根據(jù)集合元素的大小,TreeSet將它們以升序排列。如果需要實(shí)現(xiàn)定制排序,例如以降序排列,則可以通過Comparator接口的幫助。
class M { int age; public M(int age) { this.age = age; } public String toString() { return "M[age:" + age + "]"; } } public class TreeSetTest4 { public static void main(String[] args) { // 此處Lambda表達(dá)式的目標(biāo)類型是Comparator TreeSet ts = new TreeSet((o1 , o2) -> { M m1 = (M)o1; M m2 = (M)o2; // 根據(jù)M對象的age屬性來決定大小,age越大,M對象反而越小 return m1.age > m2.age ? -1 : m1.age < m2.age ? 1 : 0; }); ts.add(new M(5)); ts.add(new M(-3)); ts.add(new M(9)); System.out.println(ts); } }EnumSet類
EnumSet是一個(gè)專為枚舉類設(shè)計(jì)的集合類,EnumSet中的所有元素都必須是指定枚舉類型的枚舉值,該枚舉類型在創(chuàng)建EnumSet時(shí)顯式或隱式地指定。EnumSet的集合元素也是有序的,EnumSet以枚舉值在Enum類內(nèi)的定義順序來決定集合元素的順序
EnumSet在內(nèi)部以位向量的形式存儲,EnumSet對象占用內(nèi)存很小,運(yùn)行效率很好。尤其是進(jìn)行批量操作(如調(diào)用containsAll()和retainAll()方法)時(shí),如果其參數(shù)也是EnumSet集合,則該批量操作的執(zhí)行速度也非常快
EnumSet集合不允許加入null元素,否則拋出NullPointException異常
EnumSet沒有暴露任何構(gòu)造器來創(chuàng)建該類的實(shí)例,應(yīng)通過其提供的類方法來創(chuàng)建EnumSet對象
EnumSet allOf(Class elementType): 創(chuàng)建一個(gè)包含指定枚舉類里所有枚舉值的EnumSet集合
EnumSet complementOf(EnumSet e): 創(chuàng)建一個(gè)其元素類型與指定EnumSet里元素類型相同的EnumSet集合,新EnumSet集合包含原EnumSet集合所不包含的、此類枚舉類剩下的枚舉值(即新EnumSet集合和原EnumSet集合的集合元素加起來是該枚舉類的所有枚舉值)
EnumSet copyOf(Collection c): 使用一個(gè)普通集合來創(chuàng)建EnumSet集合
EnumSet copyOf(EnumSet e): 創(chuàng)建一個(gè)指定EnumSet具有相同元素類型、相同集合元素的EnumSet集合
EnumSet noneOf(Class elementType): 創(chuàng)建一個(gè)元素類型為指定枚舉類型的空EnumSet
EnumSet of(E first,E…rest): 創(chuàng)建一個(gè)包含一個(gè)或多個(gè)枚舉值的EnumSet集合,傳入的多個(gè)枚舉值必須屬于同一個(gè)枚舉類
EnumSet range(E from,E to): 創(chuàng)建一個(gè)包含從from枚舉值到to枚舉值范圍內(nèi)所有枚舉值的EnumSet集合
enum Season { SPRING,SUMMER,FALL,WINTER } public class EnumSetTest { public static void main(String[] args) { // 創(chuàng)建一個(gè)EnumSet集合,集合元素就是Season枚舉類的全部枚舉值 EnumSet es1 = EnumSet.allOf(Season.class); System.out.println(es1); // 輸出[SPRING,SUMMER,FALL,WINTER] // 創(chuàng)建一個(gè)EnumSet空集合,指定其集合元素是Season類的枚舉值。 EnumSet es2 = EnumSet.noneOf(Season.class); System.out.println(es2); // 輸出[] // 手動添加兩個(gè)元素 es2.add(Season.WINTER); es2.add(Season.SPRING); System.out.println(es2); // 輸出[SPRING,WINTER] // 以指定枚舉值創(chuàng)建EnumSet集合 EnumSet es3 = EnumSet.of(Season.SUMMER , Season.WINTER); System.out.println(es3); // 輸出[SUMMER,WINTER] EnumSet es4 = EnumSet.range(Season.SUMMER , Season.WINTER); System.out.println(es4); // 輸出[SUMMER,FALL,WINTER] // 新創(chuàng)建的EnumSet集合的元素和es4集合的元素有相同類型, // es5的集合元素 + es4集合元素 = Season枚舉類的全部枚舉值 EnumSet es5 = EnumSet.complementOf(es4); System.out.println(es5); // 輸出[SPRING] } }
EnumSet可以復(fù)制另一個(gè)EnumSet集合中的所有元素來創(chuàng)建新的EnumSet集合,或者復(fù)制另一個(gè)Collection集合中的所有元素來創(chuàng)建新的EnumSet集合。當(dāng)復(fù)制Collection集合中的所有元素來創(chuàng)建新的EnumSet集合時(shí),要求Collection集合中的所有元素必須是同一個(gè)枚舉類的枚舉值
各Set實(shí)現(xiàn)類的性能分析HashSet的性能總比TreeSet好,特別是最常用的添加、查詢元素等操作。因?yàn)門reeSet需要額外的紅黑樹算法來維護(hù)集合元素的次序。只有當(dāng)需要保持排序的Set時(shí),才應(yīng)該使用TreeSet,否則都應(yīng)該使用HashSet
LinkedHashSet是HashSet的一個(gè)子類,對于普通的插入、刪除操作,LinkedHashSet比HashSet要略微滿意的,這是由維護(hù)鏈表所帶來的額外開銷所造成的,但由于有了鏈表,遍歷LinkedHashSet會更快
EnumSet是所有Set實(shí)現(xiàn)類中性能最好的,但它只能保存同一個(gè)枚舉的枚舉值作為集合元素
HashSet、TreeSet、EnumSet都是線程不安全的,如果有多個(gè)線程同時(shí)訪問一個(gè)Set集合,并且有超過一個(gè)線程修改了該Set集合,則必須手動保證該Set集合的同步性。通常可以通過Collections工具類的synchronizedSortedSet方法來“包裝”該Set集合。在創(chuàng)建時(shí)進(jìn)行,以防對Set集合的意外非同步訪問
SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/66398.html
摘要:集合判斷兩個(gè)元素的標(biāo)準(zhǔn)是兩個(gè)對象通過方法比較相等,并且兩個(gè)對象的方法返回值也相等。的集合元素也是有序的,以枚舉值在類內(nèi)的定義順序來決定集合元素的順序。是所有實(shí)現(xiàn)類中性能最好的,但它只能保存同一個(gè)枚舉類的枚舉值作為集合元素。 Set集合通常不能記住元素的添加順序。Set不允許包含重復(fù)的元素。 Set集合不允許包含相同的元素,如果試圖把兩個(gè)相同的元素加入同一個(gè)Set集合中,則添加操作...
Set接口 Set是一個(gè)不能包含重復(fù)元素的Collection,它模擬了數(shù)學(xué)集抽象,Set接口僅包含從Collection繼承的方法,并添加禁止重復(fù)元素的限制,Set還為equals和hashCode操作的行為添加了一個(gè)更強(qiáng)的契約,允許Set實(shí)例有意義地進(jìn)行比較,即使它們的實(shí)現(xiàn)類型不同,如果兩個(gè)Set實(shí)例包含相同的元素,則它們是相等的。 Java平臺包含三個(gè)通用的Set實(shí)現(xiàn):HashSet、Tre...
集合接口 核心集合接口封裝了不同類型的集合,如下圖所示,這些接口允許獨(dú)立于其表示的細(xì)節(jié)來操縱集合,核心集合接口是Java集合框架的基礎(chǔ),如下圖所示,核心集合接口形成層次結(jié)構(gòu)。 showImg(https://segmentfault.com/img/bVbntJW?w=402&h=146); Set是一種特殊的Collection,SortedSet是一種特殊的Set,依此類推,另請注意,層次結(jié)構(gòu)...
摘要:一概述集合是引入的新的內(nèi)置對象類型,其特點(diǎn)同數(shù)學(xué)意義的集合,即集合內(nèi)所有元素不重復(fù)元素唯一。數(shù)組集合對比數(shù)組和集合,數(shù)組可以加入重復(fù)數(shù)據(jù),而集合的所有元素是唯一的不允許重復(fù)。因此,適合臨時(shí)存放一組對象,以及存放跟對象綁定的信息。 本文同步帶你入門 帶你入門 JavaScript ES6 (五) 集合,轉(zhuǎn)載請注明出處。 前面我們學(xué)習(xí)了: for of 變量和擴(kuò)展語法 塊作用域變量和解構(gòu)...
摘要:第三階段常見對象的學(xué)習(xí)集合框架集合在實(shí)際需求中,我們常常會遇到這樣的問題,在諸多的數(shù)據(jù)中,通過其編號來尋找某一些信息,從而進(jìn)行查看或者修改,例如通過學(xué)號查詢學(xué)生信息。面試題和的區(qū)別是單列集合的頂層接口,有子接口和。 第三階段 JAVA常見對象的學(xué)習(xí) 集合框架——Map集合 showImg(https://segmentfault.com/img/remote/1460000019683...
閱讀 2402·2021-10-09 09:41
閱讀 3206·2021-09-26 09:46
閱讀 851·2021-09-03 10:34
閱讀 3191·2021-08-11 11:22
閱讀 3384·2019-08-30 14:12
閱讀 724·2019-08-26 11:34
閱讀 3355·2019-08-26 11:00
閱讀 1791·2019-08-26 10:26