Java容器源碼分析——HashSet是如何保證元素的不可重複

一、前言

HashSet的基本特點是元素不可重複,但是不能保證元素的順序;同時也是不同步的,所以多線程常見會存在線程安全問題。在開發過程中,HashSet是一個不錯的去重工具。那是具體的實現機制是怎樣的呢?馬上開始揭曉。

二、源碼解讀

特性

HashSet繼承了集合框架AbstractSet<E>,保證了集合的基本特徵,實現了接口Set包含了基本集合操作,實現了接口Cloneable支持克隆,實現了Serializable支持序列化。

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

變量 

  //Set的實現原理
  private transient HashMap<E,Object> map;

  //集合中元素的映射值,不可變,所以所有元素的都是映射值相同
  private static final Object PRESENT = new Object();

構造方法 

五個構造方法,前四個都是用力構建單純哈希表,最後一個僅是構造函數由LinkedHashSet使用

    //無參構造函數HashSet的實現機制就是HashMap
    public HashSet() {
        map = new HashMap<>();
    }
    //構造包含指定元素集合的set,map的初始化容量:最小爲16,最大等於加入集合大小的除0.75+1
    //然後加集合加入到map中
    public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }
    //構造一個指定大小和負載係數的Set集合(map)
    public HashSet(int initialCapacity, float loadFactor) {
        map = new HashMap<>(initialCapacity, loadFactor);
    }
    //構造一個指定大小Set,無負載系統
    public HashSet(int initialCapacity) {
        map = new HashMap<>(initialCapacity);
    }
    //構造函數僅由LinkedHashSet使用
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }   

主要方法 

從下面的方法中,可以看出對Set集合操作實際上是對HashMap的操作,只是key不同,value相同。

    //迭代 
    public Iterator<E> iterator() {
         return map.keySet().iterator();
    }
    //集合大小
    public int size() {
         return map.size();
    }
    //判斷集合是否爲空
    public boolean isEmpty() {
        return map.isEmpty();
    }
    //集合是否包含某元素
    public boolean contains(Object o) {
        return map.containsKey(o);
    }
    //添加元素,實際只是添加key,value只是沒有含義的對象
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
    //刪除元素,實際是更加key刪除元素
    public boolean remove(Object o) {
         return map.remove(o)==PRESENT;
    }
    //清除元素
    public void clear() {
         map.clear();
    }
    //1.8新增的方法並行迭代
    public Spliterator<E> spliterator() {
        return new HashMap.KeySpliterator<E,Object>(map, 0, -1, 0, 0);
    }

 HashSet是如何實現元素不可重複的

通過源碼已知,Hash本質上就是HashMap,HashSet的元素實際上就是HashMap的key。最終要探究的其實是HashMap中的key爲什麼不能重複? 在通過查詢HashMap中的put的方法可以發現,在put元素時首先會計算key的hash值,通過hasn值來判斷元素加入的位置,同時會與已存在元素的hash比較,如果相等,繼續通過equas()比較hash值相同的兩個對象是否真的相同,如果仍然相同則不允許插入。

三、總結

HashSet的特點:

  • 元素不可重複且無序,元素可爲null
  • 非同步,不能線程安全
  • 實現機制是HashMap

備註:JDK版本:1.8.0_241

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章