集合-Set解析

一、概述

  1. Set集合與Collection集合基本相同,沒有提供額外的方法。實際上Set就是Collection,只是行為略有不同(Set不允許包含重復元素)。
  2. Set不允許包含重復元素,如果視圖把兩個相同的元素加入到同一個Set集合中,則會添加失敗,add()方法返回false,且新元素不會被加入。
  3. 加入Set的元素必須定義equals()方法以確保對象的唯一性。Set接口不保證維護元素的次序。

二、HashSet

2.1 概述

  1. HashSet是Set的典型接口實現,實現了Set接口中所有方法,并沒有額外添加方法
  2. HashSet是針對了HashMap進行封裝,其中Set中存儲的元素是存儲在HashMap的Key,但是Value值在Java和Android中實現有不同的表現,JDK1.8中使用的是一個固定的Object來當值,而在Android中則是使用HashMap本來來作為值。
  3. 既然是對HashMap的封裝,那么必然也需要Set中存儲的元素需要實現equals()和hashCode()方法。
  4. 為快速查找而設計的Set

2.2 代碼

Java

private transient HashMap<E,Object> map;//封裝的HashMap
private static final Object PRESENT = new Object();//Map需要的Values值
//幾個構造函數,都調用了相對應的HashMap的構造函數來確保對HashMap的封裝
public HashSet() {
        map = new HashMap<>();
}
public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
}
public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
}
//主要針對LinkedHashSet來封裝LinkedHashMap
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
}
//常用操作
 public boolean add(E e) {//增
        return map.put(e, PRESENT)==null;
}
public boolean remove(Object o) {//刪
        return map.remove(o)==PRESENT;
}
public boolean contains(Object o) {//查
        return map.containsKey(o);
}
public Iterator<E> iterator() {//遍歷
        return map.keySet().iterator();
}

Android

transient HashMap<E, HashSet<E>> backingMap;//值的泛型時HashSet
//構造函數,調用的全是一個沒有修飾符的構造函數,子類調的也是這個
public HashSet() {
        this(new HashMap<E, HashSet<E>>());
}
public HashSet(int capacity) {
        this(new HashMap<E, HashSet<E>>(capacity));
}
public HashSet(int capacity, float loadFactor) {
        this(new HashMap<E, HashSet<E>>(capacity, loadFactor));
}
public HashSet(Collection<? extends E> collection) {
        this(new HashMap<E, HashSet<E>>(collection.size() < 6 ? 11 : collection
                .size() * 2));
        for (E e : collection) {
            add(e);
        }
}
HashSet(HashMap<E, HashSet<E>> backingMap) {
        this.backingMap = backingMap;
}
//常用操作
@Override
public boolean add(E object) {//增
        return backingMap.put(object, this) == null;
}
@Override
public boolean remove(Object object) {//刪
        return backingMap.remove(object) != null;
}
@Override
public boolean contains(Object object) {//查詢,包含
        return backingMap.containsKey(object);
}
@Override
public Iterator<E> iterator() {//遍歷
        return backingMap.keySet().iterator();
}

三、LinkedTreeSet

3.1 概述

  1. 繼承自HashSet,是對LinkedHashMap的封裝
  2. 數據的遍歷順序是采用LinkedHashMap相關的遍歷順序
  3. 具有HashSet的查詢數據,且內部使用鏈表維護元素的順序,于是在使用迭代器遍歷Set是,結果會按元素插入的次序顯示。

3.2 代碼

構造函數都是調用父類的默認構造函數

Java

public class LinkedHashSet<E>
    extends HashSet<E>
    implements Set<E>, Cloneable, java.io.Serializable {

public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
}
public LinkedHashSet(int initialCapacity) {
        super(initialCapacity, .75f, true);
}
public LinkedHashSet() {
        super(16, .75f, true);
}
public LinkedHashSet(Collection<? extends E> c) {
        super(Math.max(2*c.size(), 11), .75f, true);
        addAll(c);
}

}

Android

public class LinkedHashSet<E> extends HashSet<E> implements Set<E>, Cloneable,
        Serializable {
public LinkedHashSet() {
        super(new LinkedHashMap<E, HashSet<E>>());
}
public LinkedHashSet(int capacity) {
        super(new LinkedHashMap<E, HashSet<E>>(capacity));
}
public LinkedHashSet(int capacity, float loadFactor) {
        super(new LinkedHashMap<E, HashSet<E>>(capacity, loadFactor));
}
public LinkedHashSet(Collection<? extends E> collection) {
        super(new LinkedHashMap<E, HashSet<E>>(collection.size() < 6 ? 11
                : collection.size() * 2));
        for (E e : collection) {
            add(e);
        }
}
}

四、TreeSet

4.1 概述

  1. TreeSet是NavigableSet 的實現類,NavigableSet是繼承SortedSet的接口,TreeSet默認是排序的。
  2. TreeSet為了保證是有序的序列,那么它的元素必須是可比較的,或者使用比較器來比較它的元素。
  3. TreeSet是對TreeMap進行封裝,那么TreeSet的底層數據結構也和TreeMap相同

4.2 代碼

Java

private transient NavigableMap<E,Object> m;//可排序的Map
private static final Object PRESENT = new Object();//Map的值
TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
}
public TreeSet() {
        this(new TreeMap<E,Object>());//初始化一個TreeMap
}
public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));//初始化一個TreeMap
}
public TreeSet(Collection<? extends E> c) {
        this();
        addAll(c);
}
public TreeSet(SortedSet<E> s) {
        this(s.comparator());
        addAll(s);
}
//常用方法
public boolean add(E e) {
        return m.put(e, PRESENT)==null;
}
public  boolean addAll(Collection<? extends E> c) {
        // Use linear-time version if applicable
        if (m.size()==0 && c.size() > 0 &&
            c instanceof SortedSet &&
            m instanceof TreeMap) {
            SortedSet<? extends E> set = (SortedSet<? extends E>) c;
            TreeMap<E,Object> map = (TreeMap<E, Object>) m;
            Comparator<?> cc = set.comparator();
            Comparator<? super E> mc = map.comparator();
            if (cc==mc || (cc != null && cc.equals(mc))) {
                map.addAllForTreeSet(set, PRESENT);
                return true;
            }
        }
        return super.addAll(c);
}
public boolean remove(Object o) {
        return m.remove(o)==PRESENT;
}
public boolean contains(Object o) {
        return m.containsKey(o);
}
//還有一些NavigableSet或者SortedMap方法,比如獲取第一個元素,最后一個元素,前一個元素,后一個元素等
//遍歷
public Iterator<E> iterator() {//正序遍歷
        return m.navigableKeySet().iterator();
}
public Iterator<E> descendingIterator() {//倒序遍歷
        return m.descendingKeySet().iterator();
}

Android

private transient NavigableMap<E, Object> backingMap;//需要封裝的對象
private transient NavigableSet<E> descendingSet;//倒序Set
TreeSet(NavigableMap<E, Object> map) {
        backingMap = map;
}
public TreeSet() {
        backingMap = new TreeMap<E, Object>();
}
public TreeSet(Collection<? extends E> collection) {
        this();
        addAll(collection);
}
public TreeSet(Comparator<? super E> comparator) {
        backingMap = new TreeMap<E, Object>(comparator);
}
public TreeSet(SortedSet<E> set) {
        this(set.comparator());
        Iterator<E> it = set.iterator();
        while (it.hasNext()) {
            add(it.next());
        }
}
//常用方法
@Override
public boolean add(E object) {
        return backingMap.put(object, Boolean.TRUE) == null;
}
@Override
public boolean addAll(Collection<? extends E> collection) {
        return super.addAll(collection);
}
@Override
public boolean contains(Object object) {
        return backingMap.containsKey(object);
}
@Override
public boolean remove(Object object) {
        return backingMap.remove(object) != null;
}
//遍歷
@Override
public Iterator<E> iterator() {
        return backingMap.keySet().iterator();
}
public Iterator<E> descendingIterator() {
        return descendingSet().iterator();
}

五、EnumSet

5.1 概述

  1. 專為枚舉設置的集合,后續會補充

六、總結

  1. 這幾種Set可以根據需要進行旋轉。
    1.1 查詢操作較多時,并且忽略順序時,使用HashSet
    1.2 查詢、遍歷操作較多時,并且需要順序是,可以使用LinkedHashSet
    1.3 當只需要一個特定排序的集合時,這個排序如果需要自定義時,可以考慮使用TreeSet
    1.4 插入、刪除等操作,在數據量比較小時考慮使用HashSet,不用特意去考慮
    hashCode的算法,也能有較高的效率,如果數據量比較大時,可以考慮使用TreeSet畢竟TreeSet操作時間效率在O(logn)
    1.5 具體選擇哪種集合,還需要寫測試代碼進行測試。
  2. Java中Set就是對相應的Map進行一層封裝,具體可以參考下方關于Map的文章
  3. 沒有3了......

其他文章

容器解析
ArrayList解析
LinkedList解析
TreeMap解析(上)
TreeMap解析(下)
HashMap解析
LinkedHasMap解析(下)
Set解析

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 本篇文章帶你從Java源碼深入解析關于Java容器的概念。 參考文獻: Java容器相關知識全面總結 Java官方...
    Tsy遠閱讀 20,091評論 13 142
  • 以下是《瘋狂Java講義》中的一些知識,如有錯誤,煩請指正。 集合概述 Java集合可以分為Set、List、Ma...
    hainingwyx閱讀 555評論 0 1
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,779評論 18 399
  • 集合類簡介 為什么出現集合類?面向對象語言對事物的體現都是以對象的形式,所以為了方便對多個對象的操作,就要對對象進...
    阿敏其人閱讀 1,448評論 0 7
  • 今天很榮幸的參加了學校組織的家長住校活動和家長聽課活動! 第一節課是數學課,講的是《三位數乘兩位...
    閆韶坤媽媽閱讀 320評論 0 0