摘要:集合判斷兩個元素的標準是兩個對象通過方法比較相等,并且兩個對象的方法返回值也相等。的集合元素也是有序的,以枚舉值在類內的定義順序來決定集合元素的順序。是所有實現類中性能最好的,但它只能保存同一個枚舉類的枚舉值作為集合元素。
Set集合通常不能記住元素的添加順序。Set不允許包含重復的元素。
Set集合不允許包含相同的元素,如果試圖把兩個相同的元素加入同一個Set集合中,則添加操作失敗,add()方法返回false,且新元素不會被加入。
HashSet類HashSet按照Hash算法來存儲集合中的元素,因此具有很好的存取和查詢性能。
HashSet特點
不能保證元素的排列順序,順序可能與添加順序不同,順序也有可能發生變化。
HashSet不是同步的,如果多個線程同時訪問一個HashSet,假設有兩個或者兩個以上線程同時修改了HashSet集合時,則必須通過代碼來保證其同步。
集合元素值可以是null;
當HashSet集合中存入一個元素時,HashSet會調用該對象的HashCode()方法來得到該對象的hashCode值,然后根據該hashCode值決定該對象在HashSet中的存儲位置,如果有兩個元素通過equals()方法比較返回true,但他們的hashCode()方法返回值不相等,HashSet將會把他們存在不同位置,依然可以添加成功。
HashSet集合判斷兩個元素的標準是兩個對象通過equals()方法比較相等,并且兩個對象的hashCode()方法返回值也相等。
即使兩個A對象通過equals()方法比較返回true,但HashSet依然把他們當成兩個對象,即使兩個B對象的hashCode()方法返回相同值,但HashSet依然把他們當成兩個對象。
當把一個對象放入HashSet中時,如果需要重寫該對象對應類的equals()方法,則也應該重寫其hashCode()方法,規則是:如果兩個對象通過equals()方法比較返回true,這兩個對象的hashCode值也應該相同。
如果兩個對象通過equals()比較返回true,但這兩個對象的hashCode()方法返回不同的hashCode值時,這將導致HashSet會把這兩個對象保存在Hash表的不同位置,從而使兩個對象都可以添加成功,這就與Set集合規則沖突了。
如果兩個對象的hashCode()值返回的值相同,但他們通過equals()方法比較返回false時更麻煩。因為兩個對象的hashCode值相同,HashSet將試圖把他們保存在同一個位置,但又不行(否則將只剩下一個對象),所以實際上回在這個位置用鏈式結構來保存多個對象;而HashSet訪問集合元素時也是根據元素的hashCode值來快速定位的,如果HashSet中兩個以上的元素具有相同的hashCode值,將會導致性能下降。
Hash算法可以直接根據該元素的hashCode值計算出該元素的存儲位置,從而快速定位該元素。
數組是所有能存儲一組元素里最快的數據結構。
當從HashSet中訪問元素時,HashSet先計算該元素的hashCode值,也就是調用該元素的hashCode()方法的返回值,然后直接到該hashCode值對應的位置去取出該元素。這就是HashSet速度很快的原因。
HashSet中每個能存儲元素的“槽位slot”通常稱為桶bucket,如果有多個元素的hashCode值相同,但他們通過equals方法比較返回false,就需要在一個桶里存放多個元素,就會導致性能下降。
重寫hashCode方法的基本原則。
在程序運行過程中,同一個對象多次調用hashCode()方法應該返回相同的值。
當兩個對象通過equals()方法比較返回true時,hashCode()應該也返回相同值。
對象中用作equals()方法比較標準的實例變量,都應該用于計算hashCode值。
當程序把可變對象添加到HashSet中之后,盡量不要去修改該集合元素中參與計算hashCode()’equals()的實例變量,否則將會導致HashSet無法爭取操作這些集合。
LinkedHashSet類LinkedHashSet集合也是根據元素的hashCode值來決定元素的存儲位置,但它同時使用鏈表維護元素的次序,LinkedHashSet將會按元素的添加順序來訪問集合里的元素。
同樣不能允許集合元素重復,
public class LinkedHashSetTest { public static void main(String[] args) { CollectionTreeSet類collection = new LinkedHashSet<>(); collection.add("java"); collection.add("python"); //[java, python] System.out.println(collection); collection.remove("java"); collection.add("java"); //[python, java] System.out.println(collection); } }
TreeSet是StortedSet接口的實現類。TreeSet可以保證集合元素處于排序狀態。
public class TreeSetTest { public static void main(String[] args) { TreeSettreeSet = new TreeSet<>(); treeSet.add("5"); treeSet.add("4"); treeSet.add("3"); treeSet.add("2"); treeSet.add("1"); System.out.println(treeSet); System.out.println(treeSet.first());//1 System.out.println(treeSet.last());//5 //返回集合中位于指定元素之前的元素 System.out.println(treeSet.lower("4"));//3 //返回集合中位于指定元素之后的元素 System.out.println(treeSet.higher("4"));//5 //返回此set的子集,由小于指定元素的元素組成 SortedSet headSet = treeSet.headSet("4"); System.out.println(headSet);//[1, 2, 3] //返回set的子集。由大于或者等于指定元素的元素組成 SortedSet tailSet = treeSet.tailSet("4"); System.out.println(tailSet);//[4, 5] } }
Tree并不是根據元素的插入順序進行排序的,而是根據元素實際的大小來進行排序的。
與HashSet集合采用hash算法來決定元素的存儲位置不同,TreeSet是采用紅黑樹的數據結構來存儲集合元素,TreeSet支持兩種排序方法,自然排序和定制排序。默認下TreeSet采用自然排序。
自然排序
TreeSet會調用集合元素的compareTo(Object o)方法來比較元素之間的大小關系,然后將集合元素按升序排序,這種方式就是自然排序。
如果試圖把一個對象添加到TreeSet時,則該對象的類必須實現comparable接口。否則報錯
public class TreeSetErrorTest { public static void main(String[] args) { USER user = new USER("", 2); TreeSettreeSet = new TreeSet<>(); //Exception in thread "main" java.lang.ClassCastException: setTest.USER cannot be cast to java.base/java.lang.Comparable treeSet.add(user); } }
當試圖把一個對象添加到TreeSet集合時,TreeSet會調用該對象的comparaTo(Object o)方法與集合中的其他元素進行比較,這就要求集合中的其他元素與該元素時同一類的實例,也就是說,向TreeSet中添加的應該是同一個類的對象,否則也會引發ClassCastException異常。
public class TreeSetErrorTest2 { public static void main(String[] args) { TreeSet set = new TreeSet<>(); set.add(new String()); //Exception in thread "main" java.lang.ClassCastException: java.base/java.lang.String cannot be cast to java.base/java.util.Date set.add(new Date()); /* * 在添加String時,是沒有錯誤的,當添加Date對象時,TreeSet就會調用該對象的comparaTo方法與集合中的其他元素進行比較-- * Date對象的comparaTo方法無法與字符串對象比較大小,所以引發異常 * */ } }
TreeSet只能添加同一種類型的對象,
當把一個對象加入TreeSet集合中時,TreeSet調用該對象的compareTo(Obejct o)方法與容器中的其他對象比較大小,然后根據紅黑樹結構找到他的存儲位置,如果兩個對象通過compareTo(Object o)方法比較相等,新對象將無法添加到TreeSet集合中。
TreeSet集合判斷兩個對象是夠相等的唯一標準是:如果通過compareTo方法比較返回0,TreeSet則會認為他們相等,否則就認為他們不相等。
當需要把一個對象放入TreeSet中,重寫該對象對應類的equals方法時,應保證該方法與compareTo方法有一致的結果,其規則是,如果兩個對象通過equals方法比較返回true時,這兩個對象通過compareTo方法比較應返回0;
TreeSet可以刪除沒有被修改實例變量,且不與其他被修改實例變量的對象重復的對象。P309
推薦不要修改放入HashSet和TreeSet集合中元素的關鍵實例變量。
定制排序public class MSort { public static void main(String[] args) { TreeSettreeSet = new TreeSet<>((o1,o2)->{ M m1 = o1; M m2 = o2; return Integer.compare(m1.a, m2.a); }); treeSet.add(new M(12)); treeSet.add(new M(1232)); treeSet.add(new M(121)); //[12, 121, 1232] System.out.println(treeSet); } }
當通過Comparator對象或Lambda表達式來實現TreeSet的定制排序時,依然不可以向TreeSet中添加類型不同的對象,否則會引發ClassCastException異常,使用定制排序時,TreeSet對集合元素排序不管集合元素本身的大小,而是由Comparator對象或Lambda表達式。負責集合元素的排序規則,TreeSet判斷兩個集合元素相等的標準是:通過Comparator比較兩個元素返回了0,這樣TreeSet不會把第二個元素添加到集合中。
EnumSet類EnumSet是一個轉為枚舉類設計的集合類,EnumSet中的所有元素都必須是指定枚舉類型的枚舉值,該枚舉值在創建EnumSet時顯示或隱式地指定。EnumSet的集合元素也是有序的,EnumSet以枚舉值在Enum類內的定義順序來決定集合元素的順序。
EnumSet在內部以位向量的形式存儲,這種存儲形式非常緊湊高效,因此EnumSet對象占用內存很小,運行效率好,尤其是在進行批量操作的時候。
EnumSet集合不允許加入NULL;
public class SeasonEnumSetTest { public static void main(String[] args) { //創建一個EnumSet集合,集合元素是Season的全部枚舉 EnumSetenumSet = EnumSet.allOf(Season.class); System.out.println(enumSet);//[SPTING, SUMMER, FALL, WINTER] //創建一個空集合,指定其集合元素是Season類的枚舉類 EnumSet noneOf = EnumSet.noneOf(Season.class); System.out.println(noneOf);//[] noneOf.add(Season.FALL); noneOf.add(Season.WINTER); System.out.println(noneOf);//[FALL, WINTER] //利用現有枚舉進行創建EnumSet集合 EnumSet of = EnumSet.of(Season.SPTING,Season.SUMMER); System.out.println(of);//[SPTING, SUMMER] //創建幾個從begin到end之間的枚舉作為新集合的元素 EnumSet range = EnumSet.range(Season.SUMMER, Season.WINTER); System.out.println(range);//[SUMMER, FALL, WINTER] //range與complementof枚舉值和是Season的全部枚舉 EnumSet complementOf = EnumSet.complementOf(range); System.out.println(complementOf);//[SPTING] } }
當試圖復制一個Collection集合里的元素來創建EnumSet集合時,必須保證Collection集合里的所有元素都是同一個枚舉類的枚舉值。
Set實現類的性能分析HashSet的性能總是比TreeSet好,特別是最常用的添加,查詢元素等操作,因為TreeSet需要額外的紅黑樹算法來維護集合元素的次序,只有當需要一個保持排序的Set時,才應該使用TreeSet,否則都應該使用HashSet。
LinkedHashSet對于普通的插入,刪除操作,LinkedHashSet比HashSet要略慢一點,這是由維護鏈表所帶來的額外開銷造成的,但由于有了鏈表,遍歷LinkedHashSet會更快。
EnumSet是所有Set實現類中性能最好的,但它只能保存同一個枚舉類的枚舉值作為集合元素。
Set的三個實現類HashSet,TreeSet和EnumSet都是線程不安全的。
如果有多個線程同時訪問Set集合那么需要手動保證該Set集合的同步性。
Collections.synchronizedSortedSet(new TreeSet(...));
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69316.html
Set接口 Set是一個不能包含重復元素的Collection,它模擬了數學集抽象,Set接口僅包含從Collection繼承的方法,并添加禁止重復元素的限制,Set還為equals和hashCode操作的行為添加了一個更強的契約,允許Set實例有意義地進行比較,即使它們的實現類型不同,如果兩個Set實例包含相同的元素,則它們是相等的。 Java平臺包含三個通用的Set實現:HashSet、Tre...
集合接口 核心集合接口封裝了不同類型的集合,如下圖所示,這些接口允許獨立于其表示的細節來操縱集合,核心集合接口是Java集合框架的基礎,如下圖所示,核心集合接口形成層次結構。 showImg(https://segmentfault.com/img/bVbntJW?w=402&h=146); Set是一種特殊的Collection,SortedSet是一種特殊的Set,依此類推,另請注意,層次結構...
摘要:一概述集合是引入的新的內置對象類型,其特點同數學意義的集合,即集合內所有元素不重復元素唯一。數組集合對比數組和集合,數組可以加入重復數據,而集合的所有元素是唯一的不允許重復。因此,適合臨時存放一組對象,以及存放跟對象綁定的信息。 本文同步帶你入門 帶你入門 JavaScript ES6 (五) 集合,轉載請注明出處。 前面我們學習了: for of 變量和擴展語法 塊作用域變量和解構...
摘要:第三階段常見對象的學習集合框架集合在實際需求中,我們常常會遇到這樣的問題,在諸多的數據中,通過其編號來尋找某一些信息,從而進行查看或者修改,例如通過學號查詢學生信息。面試題和的區別是單列集合的頂層接口,有子接口和。 第三階段 JAVA常見對象的學習 集合框架——Map集合 showImg(https://segmentfault.com/img/remote/1460000019683...
閱讀 2066·2021-11-11 16:54
閱讀 1046·2021-10-12 10:12
閱讀 386·2019-08-30 15:43
閱讀 652·2019-08-29 13:15
閱讀 1080·2019-08-29 13:12
閱讀 1531·2019-08-26 12:09
閱讀 1662·2019-08-26 10:24
閱讀 2263·2019-08-26 10:15