天天看點

Java集合之Set集合Set接口

Set接口

首先Set集合不能擁有相同的元素,它與Collection的方法上沒有太多的差別,隻是行為不同,即不能有相同元素.

HashSet實作類

HashSet是Set的接口的典型實作,大多數時都會使用HashSet,使用的時Hash算法來存儲集合中的元,是以有很好的存取和查找性能.

HashSet的特點:

1.不能保證元素的排列順序,順序可能和添加順序不同,可能會有變化

2.HashSet不是同步的,可以通過代碼保證其同步

3.集合的元素值可以是null

當一個HashSet集合存入一個元素時,HashSet會調用該對象的hashCode()方法來得到hashCode值,根據值決定HashSet中的存儲位置.

但如果當兩對象的hashCode值不相等,則不會調用equal()方法,即就算兩者的值是相等,HashSet會将它們存儲在不同位置,依然可以添加成功,這是不可取的,違反了Set的規則

當兩對象的hashCode值相等,調用equal值不相等時,HashSet将會試圖将它們使用鍊式結構儲存在同一位置,但這種情況會導緻HashSet的性能下降,因為HashSet是根據元素的hashCode值來快速定位的

是以當某個類的對象儲存到HashSet集合中,重寫這個類的equals()方法和hashCode()方法時,應盡量保證兩個對象通過equals()方法比較傳回true時,他們的hashCode()方法傳回值也為true

當HashSet集合中添加了可變對象也要極其小心,若是修改了集合元素中參與計算hashCode(),equals()的執行個體變量,可能會導緻HashSet無法正确操作這些集合元素,如下

import java.util.HashSet;

import java.util.Iterator;

import java.util.Set;

public class HashSetTest {

    public static void main(String[] args) {

        Set hs = new HashSet();

        hs.add(new A(1));

        hs.add(new A(5));

        hs.add(new A(10));

        hs.add(new A(20));

        System.out.println("原來中集合的元素:"+hs+"     ");

        System.out.println("-------------------------");

        Iterator it = hs.iterator();

        //取出第一個元素

        A one = (A) it.next();

        one.count = 5;

        System.out.println("修改後的集合元素:"+ hs + "     ");

        System.out.println("-------------------------");

        //删除一個count為5的對象

        hs.remove(new A(5));

        System.out.println("删除了一個集合元素為5的元素:" + hs + "  ");

        System.out.println("-------------------------");

        System.out.println("是否包含了1的對象:"  +hs.contains(new A(1)));

        System.out.println("是否包含了5的對象:"  +hs.contains(new A(5)));

    }

}

控制台列印結果

原來中集合的元素:[A的count值:1, A的count值:20, A的count值:5, A的count值:10]     

-------------------------

修改後的集合元素:[A的count值:5, A的count值:20, A的count值:5, A的count值:10]     

-------------------------

删除了一個集合元素為5的元素:[A的count值:5, A的count值:20, A的count值:10]  

-------------------------

是否包含了1的對象:false

是否包含了5的對象:false

LinkedHashSet

LinkedHashSet是HashSet的子類,它與HashSet的差別是,元素的順序總是與添加的順序,這是使用了連結清單維護元素的次序,是以性能略低于HashSet的性能,但在疊代通路Set裡的全部元素時将有很好的性能,因為它以連結清單來維護内部順序.

TreeSet

TreeSet是SortSet接口的實作類,TreeSet不是以插入順序進行排序的,而是根據元素實際值的大小來進行排序的.

TreeSet會調用集合元素的compareTo(Object obj)方法來比較元素之間的大小的關系,然後将集合元素按升序排序,為自然排序.

Java9改進了TreeSet實作,采用自然排序的Set集合的元素沒有實作Comparable,程式會引發ClassCaseException異常

TreeSet和HashSet一樣不要修改執行個體變量,會導緻無法删除變量,為了讓程式健壯,不要修改放入HashSet和TreeSet集合中元素的關鍵執行個體變量.

定制排序,可以通過Comparator接口的幫助來制定自己的排序代碼

EnumSet

EnumSet是一個轉為枚舉類的集合類,EnumSet中所有的元素都必須是指定的枚舉類型的枚舉值,其集合元素也是有序的,EnumSet以枚舉在Enum類内的定義順序來決定集合元素的順序.

EnumSet在内部以位向量的形式存儲,這種存儲形式非常緊湊,高效,是以EnumSet對象占用記憶體很小,而且運作效率好.

EnumSet步允許加入null元素

各Set實作類的性能分析

HashSet和TreeSet是Set兩個典型實作,HashSet的性能總比TreeSet好,特别是在添加,查詢元素等操作,因為TreeSet需要額外的紅黑數算法來維護集合元素的次序.

LinkedHashSet因為有了連結清單的維護,在周遊時會比較友善

EnumSet性能最好

上述的Set的實作類,線程都是不安全的,可以通過Collections.synchronizedSortedSet()來實作線程安全