1. 程式人生 > >四,Java集合類(2)——Set介面及其實現類

四,Java集合類(2)——Set介面及其實現類

1,Set介面及其實現類

Set集合與Collection基本相同,沒有提供任何額外的方法。實際上Set就是Collection,只是行為略有不同。Set集合不允許包含相同的元素,如果試圖把兩個相同的元素加入同一個Set集合中,新增操作失敗,add()方法返回false,且新元素不會被加入。

1.2,HashSet類

HashSet按Hash演算法來儲存集合中的元素。HashSet有以下特點:

  1. 不能保證元素的排列順序,輸入順序和輸出順序可能不同。
  2. HashSet不是同步的,若有兩個以上的執行緒修改集合時候,必須程式碼保證同步。
  3. 集合元素可以為null。

如果HashSet中要存放類物件,則該物件需要重寫equals()和hashCode()方法。規則是若equals()返回的值是true,則這兩個物件的hashCode值也應該是相同的。

  • equals返回的是true,hashCode返回的是兩個不同的值,則HashSet會將相同的數值存放在不同的位置,這樣就和Set存放不相同的數值的規則起衝突,不可以採用。
  • equals返回的是true,hashCode返回的是兩個相同的值,則HashSet會將相同的數值在同一個位置上以連結串列的形式儲存。
package com.practice.collection;

import java.util.HashSet;

class A {
    @Override
    public boolean equals(Object arg0) {
        // TODO Auto-generated method stub
        return true;
    }
}
class B{
    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        return 1;
    }
}
class C{
    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        return 2;
    }
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        return true;
    }
}
public class HashSetTest {

    public static void main(String[] args) {
        HashSet books = new HashSet();
        books.add(new A());
        books.add(new A());
        books.add(new B());
        books.add(new B());
        books.add(new C());
        books.add(new C());
        System.out.println(books);
    }
}

1.3,LinkedHashSet類

LindedHahSet集合也是根據元素的hashCode值來決定元素的儲存位置,但它是使用連結串列的形式維護元素的次序。當遍歷LinkedHashSet集合裡的元素時,LinkedHashSet會按元素的新增順序來訪問集合裡的元素。LinkedHashSet需要維護元素的插入順序,因此效能略低於HashSet的效能。

package com.practice.collection;

import java.util.LinkedHashSet;

public class LinkedHashSetTest {

    public static void main(String[] args) {
        LinkedHashSet linkedHashSet = new LinkedHashSet();
        linkedHashSet.add("Java從入門到出門");
        linkedHashSet.add("PHP從入門到放棄");
        linkedHashSet.add("Spring從入門到沒門");
        linkedHashSet.add("Hibernate從入門到精通");
        System.out.println(linkedHashSet);
    }
}

1.4,TreeSet類

TreeSet可以確保集合元素處於排序狀態,這種排序狀態是根據元素的大小來排序的,並不是根據元素的插入順序來進行排序的。

package com.practice.collection;

import java.util.TreeSet;


public class TreeSetTest {

    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        treeSet.add(1);
        treeSet.add(4);
        treeSet.add(5);
        treeSet.add(2);
        treeSet.add(3);
        System.out.println(treeSet);
        /*輸出集合中第一個元素*/
        System.out.println(treeSet.first());
        /*輸出集合中最後一個元素*/
        System.out.println(treeSet.last());
        /*輸出大於2,小於4的子集*/
        System.out.println(treeSet.subSet(2, 4));
        /*輸出大於2的子集,如果集合中有2,則還會輸出2*/
        System.out.println(treeSet.tailSet(2));
        /*輸出小於3的子集,不包括3*/
        System.out.println(treeSet.headSet(3));
    }
}

1.5,EnumSet類

EnumSet是一個專門為列舉類設計的集合類,該集合中的元素都必須是指定列舉型別的列舉值,該列舉型別在建立EnumSet是顯示或隱式地指定。EnumSet的集合元素也是有序的,EnumSet以列舉值在Enum類內的定義順序來決定集合元素的順序。同時該集合不允許加入null元素,如果試圖加入null元素,EnumSet將會丟擲空指標異常。

package com.practice.collection;

import java.util.EnumSet;

enum Season{
    SPRING,SUMMER,FALL,WINTER
}
public class EnumSetTest {

    public static void main(String[] args) {
        /*建立一個包含指定列舉類裡所有列舉值的EnumSet集合*/
        EnumSet enumSet = EnumSet.allOf(Season.class);
        System.out.println(enumSet);
        /*建立一個元素型別為指定列舉型別的空的EnumSet集合*/
        EnumSet enumSet2 = EnumSet.noneOf(Season.class);
        System.out.println(enumSet2);
        enumSet2.add(Season.WINTER);
        enumSet2.add(Season.SPRING);
        System.out.println(enumSet2);
        /*建立一個包含一個或多個列舉值的EnumSet集合,傳入的多個列舉值必須屬於同一個列舉類*/
        EnumSet enumSet3 = EnumSet.of(Season.FALL, Season.WINTER, Season.SPRING);
        System.out.println(enumSet3);
        /*建立一個包含從from列舉值到to列舉值範圍內所有列舉值的EnumSet集合*/
        EnumSet enumSet4 = EnumSet.range(Season.SPRING, Season.WINTER);
        System.out.println(enumSet4);
        /*建立一個其元素型別與指定EnumSet裡元素型別相同的的EnumSet集合
        *新EnumSet集合包含原來EnumSet集合所不包含的,此列舉類剩下的列舉值
        */
        EnumSet enumSet5 = EnumSet.complementOf(enumSet4);
        System.out.println(enumSet5);
    }
}

2,Set實現類效能分析

HashSet和TreeSet是Set介面的典型實現。對於HashSet和TreeSet如何選擇?


HashSet的效能總是比TreeSet好,特別是最常用的新增,查詢元素等操作。TreeSet需要額外的紅黑樹演算法來維護集合元素的次序。只有當需要一個保持排序的Set時候,才應該使用TreeSet。否則都應該使用HashSet。

LinkedHashSet是HashSet的子類,在正常的插入,刪除操作,LinkedHashSet比HashSet要略微慢一點,因為LinkedHashSet需要額外的維護自己的連結串列,也正是因為存在連結串列,遍歷LinkedHashSet相比較於HashSet要快點。
與其他三個相比較而言,EnumSet是效能相對比較好的。但是這個類只能使用同一個列舉類作為集合元素。

Set的三個實現類HashSet,TreeSet,EnumSet都是非執行緒安全的,所以在多個執行緒對集合訪問修改時候要保證集合的同步性。通常可以通過Collections工具類的synchronizedSortedSet方法來包裝該Set集合。該操作最好在建立時進行,以防止對Set集合的意外非同步訪問

SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));