當前位置:
首頁 > 知識 > Java集合-HashSet

Java集合-HashSet

HashSet類,是存在於java.util包中的類 。同時也被稱為集合,該容器中只能存儲不重複的對象。底層是由HashMap來存儲的,因為HashSet不能重複,你知道HashMap的鍵不能重複就明白了這一個原理了,所以對於HashMap很熟悉的話對於HashSet就能夠很快的知道底層實現。HashMap傳送門(HashMap源碼分析)。

HashSet概述

此類實現了Set介面,由哈希表(實際上是HashMap實例)支持。 對集合的迭代次序不作任何保證; 特別是不會保證這種順序會持久不變(不保證循環元素的順序,所以就有可能是有序的,也有可能是無序的),此類允許null元素。

這個類基本操作為add,remove,contains和size提供了穩定的時間性能,假設哈希函數在桶中正確分散元素。 迭代該集合需要時間與HashSet實例的大小(元素數量)和後台HashMap實例的「容量」(桶數)的總和成比例。 因此,如果迭代性能很重要,不要將初始容量設置得太高(或負載因子太低)是非常重要的。

請注意,此實現不同步。如果多個線程並發訪問哈希集,並且至少一個線程修改該集合,則必須在外部進行同步。這通常通過在自然封裝集合的某個對象上進行同步來實現。

如果沒有這樣的對象存在,則該集合應該使用Collections.synchronizedSet方法「包裝」。這最好在創建時完成,以防止意外的非同步訪問集:

Set s = Collections.synchronizedSet(new HashSet(...));

這個類的迭代器方法返回的迭代器是快速失敗的:如果在迭代器創建之後的任何時候該集合被修改,除了通過迭代器自己的remove方法之外,迭代器會以任何方式拋出ConcurrentModificationException異常。因此, 在並發修改時,迭代器會很快失效,而不是在未來不確定的時間內發生不確定性行為。

請注意,迭代器的快速失敗行為無法保證,因為一般來說,在不同步並發修改的情況下,無法做出任何硬性保證。 Fail-fast迭代器會儘力拋出ConcurrentModificationException異常。因此,編寫依賴於該異常的程序的正確性是錯誤的:迭代器的快速失敗行為只能用於檢測錯誤。(以上翻譯於JDK1.7,有錯誤請指出)

HashSet源碼分析2.1、定義

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

繼承AbstractSet ,該類覆蓋了 equals 和 hashCode 方法,以確保兩個相等的集返回相同的散列碼。若兩個集大小相等且包含相同元素,則這兩個集相等。按定義,集散列碼是集中元素散列碼的總和。因此,不論集的內部順序如何,兩個相等的集會報告相同的散列碼(百度百科)。

實現了Set介面,Set定義了集合的一些基本操作,如add、remove等等。實現了克隆介面Cloneable,序列化介面Serializable。

2.2、屬性

static final long serialVersionUID = -5024744406713321676L;//序列版本號

private transient HashMap map;//私有的HashMap,E為鍵,Object為值,是不是看到底層的東西了,哈哈

private static final Object PRESENT = new Object;//與支持Map中的對象關聯的虛擬值,屬性就三個,簡單粗暴。

2.3、構造方法

    public HashSet {//構造一個新的空集合; 後台HashMap實例具有默認初始容量(16)和負載因子(0.75)。
map = new HashMap<>;
    }

   public HashSet(Collection c) {//構造一個包含指定集合中的元素的新集合。 HashMap使用默認負載因子(0.75)創建,初始容量足以包含指定集合中的元素。
map = new HashMap<>(Math.max((int) (c.size/.75f) + 1, 16));//如果c.size/0.75值大於16則大小為c.size/0.75+1,否則默認16.
addAll(c);
    }

    public HashSet(int initialCapacity, float loadFactor) {//構造一個新的空集合; 後台HashMap實例具有指定的初始容量和指定的負載因子。
map = new HashMap<>(initialCapacity, loadFactor);//初始容量,負載因子
    }

   public HashSet(int initialCapacity) {//構造一個新的空集合; 後台HashMap實例具有指定的初始容量和默認負載因子(0.75)。
map = new HashMap<>(initialCapacity);
   }

   HashSet(int initialCapacity, float loadFactor, boolean dummy) {//構造一個新的,空的LinkedHashMap。 (此包私有構造函數僅由LinkedHashSet使用。)後綴HashMap實例是具有指定初始容量和指定負載因子的LinkedHashMap。
map = new LinkedHashMap<>(initialCapacity, loadFactor);
   }

2.4、add方法

  public boolean add(E e) {
return map.put(e, PRESENT)==null;//map增加,終於看出來底層是map了
  }

2.5、remove方法

  public boolean remove(Object o) {//如果存在,則從該集合中刪除指定的元素。
return map.remove(o)==PRESENT;
  }

2.6、clear方法

 public void clear {//從該集合中刪除所有元素。此調用返回後,該集合將為空。
map.clear;//使用map的clear
 }

2.7、clone方法

  public Object clone {//返回此 HashSet 實例的淺層副本:元素本身不被克隆。
try {
HashSet newSet = (HashSet) super.clone;//HashSet克隆
newSet.map = (HashMap) map.clone;//map克隆
return newSet;
} catch (CloneNotSupportedException e) {
throw new InternalError;
}
  }

HashSet總結

HashSet的底層採用HashMap實現,只要對HashMap熟悉,HashSet毫無壓力。要記住以下幾點:

1、HashSet可以插入Null.

2、HashSet的元素不能重複。

3、HashSet的遍歷是可能有序可能無序的。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 科技優家 的精彩文章:

為什麼多線程、junit 中無法使用spring 依賴注入?
OS X 和iOS 中的多線程技術(上)
View Components as Tag Helpers,離在線模板編輯又進一步
淺談MVC Form認證
asp.net core中負載均衡場景下http重定向https的問題

TAG:科技優家 |