1.??? HashSet 概述:
?? ? HashSet 實現 Set 接口,由哈希表(實際上是一個 HashMap 實例)支持。它不保證 set ? 的迭代順序;特別是它不保證該順序恒久不變。此類允許使用 null 元素。
?
2.??? HashSet 的實現:
?? ? 對于 HashSet 而言,它是基于 HashMap 實現的, HashSet 底層使用 HashMap 來保存所有元素,因此 HashSet ? 的實現比較簡單,相關 HashSet 的操作,基本上都是 直接調用底層 HashMap 的相關方法來完成 , 我們應該為保存到HashSet中的對象覆蓋hashCode()和equals(),因為再將對象加入到HashSet中時,會首先調用hashCode方法計算出對象的hash值,接著根據此hash值調用HashMap中的hash方法,得到的值& (length-1)得到該對象在hashMap的transient Entry[] table中的保存位置的索引,接著找到數組中該索引位置保存的對象,并調用equals方法比較這兩個對象是否相等,如果相等則不添加,如果不等,則添加到該數組索引對應的鏈表中。
------------------------------------------------------------------------------------------
Set的實現類的集合對象中不能夠有重復元素,HashSet也一樣他是使用了一種標識來確定元素的不重復,HashSet用一種算法來保證HashSet中的元素是不重復的,??? HashSet采用哈希算法,底層用數組存儲數據。 默認初始化容量16,加載因子0.75
?Object類中的hashCode()的方法是所有子類都會繼承這個方法,這個方法 會用Hash算法算出一個Hash(哈希)碼值返回,HashSet會用Hash碼值去和數組長度取模,?模(這個模就是對象要存放在數組中的位置)相同時才會判斷數組中的元素和要加入的對象的內容是否相同,如果不同才會添加進去。
?Hash算法是一種散列算法。
??Set hs=new HashSet();
?
??hs.add(o);
???? |
???????? o.hashCode();
???? |
??o%當前總容量? (0--15)
???? |????????????
?
???? |?????????? 不發生沖突
??????? 是否發生沖突-----------------直接存放
???? |
???? | 發生沖突
???? |????????????? 假(不相等)
??????? o1.equals(o2)-------------------找一個空位添加
???? |
???? |? 是(相等)
???????? 不添加
?
?覆蓋hashCode()方法的原則:
? 1、一定要讓那些我們認為相同的對象返回相同的hashCode值
? 2、盡量讓那些我們認為不同的對象返回不同的hashCode值,否則,就會增加沖突的概率。
??3、盡量的讓hashCode值散列開(兩值用異或運算可使結果的范圍更廣)
?注意:所以
要存入HashSet的集合對象中的自定義類必須覆蓋hashCode(),equals()兩個方法
,才能保證集合中元素不重復。在覆蓋equals()和hashCode()方法時,?要使相同對象的hashCode()方法返回相同值,覆蓋equals()方法再判斷其內容。為了保證效率,所以在覆蓋hashCode()方法時,?也要盡量使不同對象盡量返回不同的Hash碼值。
?如果數組中的元素和要加入的對象的hashCode()返回了相同的Hash值(相同對象),才會用equals()方法來判斷兩個對象的內容是否相同。
------------------------------------------------------------------------------------------
?
? HashSet 的源代碼如下:
- public ? class ?HashSet<E>??
- ???? extends ?AbstractSet<E>??
- ???? implements ?Set<E>,?Cloneable,?java.io.Serializable??
- {??
- ???? static ? final ? long ?serialVersionUID?=?-5024744406713321676L;??
- ??
- ???? //?底層使用HashMap來保存HashSet中所有元素。 ??
- ???? private ? transient ?HashMap<E,Object>?map;??
- ??????
- ???? //?定義一個虛擬的Object對象作為HashMap的value,將此對象定義為static?final。 ??
- ???? private ? static ? final ?Object?PRESENT?=? new ?Object();??
- ??
- ???? /** ?
- ?????*?默認的無參構造器,構造一個空的HashSet。 ?
- ?????*? ?
- ?????*?實際底層會初始化一個空的HashMap,并使用默認初始容量為16和加載因子0.75。 ?
- ?????*/ ??
- ???? public ?HashSet()?{??
- ????map?=? new ?HashMap<E,Object>();??
- ????}??
- ??
- ???? /** ?
- ?????*?構造一個包含指定collection中的元素的新set。 ?
- ?????* ?
- ?????*?實際底層使用默認的加載因子0.75和足以包含指定 ?
- ?????*?collection中所有元素的初始容量來創建一個HashMap。 ?
- ?????*?@param?c?其中的元素將存放在此set中的collection。 ?
- ?????*/ ??
- ???? public ?HashSet(Collection<?? extends ?E>?c)?{??
- ????map?=? new ?HashMap<E,Object>(Math.max(( int )?(c.size()/.75f)?+? 1 ,? 16 ));??
- ????addAll(c);??
- ????}??
- ??
- ???? /** ?
- ?????*?以指定的initialCapacity和loadFactor構造一個空的HashSet。 ?
- ?????* ?
- ?????*?實際底層以相應的參數構造一個空的HashMap。 ?
- ?????*?@param?initialCapacity?初始容量。 ?
- ?????*?@param?loadFactor?加載因子。 ?
- ?????*/ ??
- ???? public ?HashSet( int ?initialCapacity,? float ?loadFactor)?{??
- ????map?=? new ?HashMap<E,Object>(initialCapacity,?loadFactor);??
- ????}??
- ??
- ???? /** ?
- ?????*?以指定的initialCapacity構造一個空的HashSet。 ?
- ?????* ?
- ?????*?實際底層以相應的參數及加載因子loadFactor為0.75構造一個空的HashMap。 ?
- ?????*?@param?initialCapacity?初始容量。 ?
- ?????*/ ??
- ???? public ?HashSet( int ?initialCapacity)?{??
- ????map?=? new ?HashMap<E,Object>(initialCapacity);??
- ????}??
- ??
- ???? /** ?
- ?????*?以指定的initialCapacity和loadFactor構造一個新的空鏈接哈希集合。 ?
- ?????*?此構造函數為包訪問權限,不對外公開,實際只是是對LinkedHashSet的支持。 ?
- ?????* ?
- ?????*?實際底層會以指定的參數構造一個空LinkedHashMap實例來實現。 ?
- ?????*?@param?initialCapacity?初始容量。 ?
- ?????*?@param?loadFactor?加載因子。 ?
- ?????*?@param?dummy?標記。 ?
- ?????*/ ??
- ????HashSet( int ?initialCapacity,? float ?loadFactor,? boolean ?dummy)?{??
- ????map?=? new ?LinkedHashMap<E,Object>(initialCapacity,?loadFactor);??
- ????}??
- ??
- ???? /** ?
- ?????*?返回對此set中元素進行迭代的迭代器。返回元素的順序并不是特定的。 ?
- ?????*? ?
- ?????*?底層實際調用底層HashMap的keySet來返回所有的key。 ?
- ?????*?可見HashSet中的元素,只是存放在了底層HashMap的key上, ?
- ?????*?value使用一個static?final的Object對象標識。 ?
- ?????*?@return?對此set中元素進行迭代的Iterator。 ?
- ?????*/ ??
- ???? public ?Iterator<E>?iterator()?{??
- ???? return ?map.keySet().iterator();??
- ????}??
- ??
- ???? /** ?
- ?????*?返回此set中的元素的數量(set的容量)。 ?
- ?????* ?
- ?????*?底層實際調用HashMap的size()方法返回Entry的數量,就得到該Set中元素的個數。 ?
- ?????*?@return?此set中的元素的數量(set的容量)。 ?
- ?????*/ ??
- ???? public ? int ?size()?{??
- ???? return ?map.size();??
- ????}??
- ??
- ???? /** ?
- ?????*?如果此set不包含任何元素,則返回true。 ?
- ?????* ?
- ?????*?底層實際調用HashMap的isEmpty()判斷該HashSet是否為空。 ?
- ?????*?@return?如果此set不包含任何元素,則返回true。 ?
- ?????*/ ??
- ???? public ? boolean ?isEmpty()?{??
- ???? return ?map.isEmpty();??
- ????}??
- ??
- ???? /** ?
- ?????*?如果此set包含指定元素,則返回true。 ?
- ?????*?更確切地講,當且僅當此set包含一個滿足(o==null???e==null?:?o.equals(e)) ?
- ?????*?的e元素時,返回true。 ?
- ?????* ?
- ?????*?底層實際調用HashMap的containsKey判斷是否包含指定key。 ?
- ?????*?@param?o?在此set中的存在已得到測試的元素。 ?
- ?????*?@return?如果此set包含指定元素,則返回true。 ?
- ?????*/ ??
- ???? public ? boolean ?contains(Object?o)?{??
- ???? return ?map.containsKey(o);??
- ????}??
- ??
- ???? /** ?
- ?????*?如果此set中尚未包含指定元素,則添加指定元素。 ?
- ?????*?更確切地講,如果此?set?沒有包含滿足(e==null???e2==null?:?e.equals(e2)) ?
- ?????*?的元素e2,則向此set?添加指定的元素e。 ?
- ?????*?如果此set已包含該元素,則該調用不更改set并返回false。 ?
- ?????* ?
- ?????*?底層實際將將該元素作為key放入HashMap。 ?
- ?????*?由于HashMap的put()方法添加key-value對時,當新放入HashMap的Entry中key ?
- ?????*?與集合中原有Entry的key相同(hashCode()返回值相等,通過equals比較也返回true), ?
- ?????*?新添加的Entry的value會將覆蓋原來Entry的value,但key不會有任何改變, ?
- ?????*?因此如果向HashSet中添加一個已經存在的元素時,新添加的集合元素將不會被放入HashMap中, ?
- ?????*?原來的元素也不會有任何改變,這也就滿足了Set中元素不重復的特性。 ?
- ?????*?@param?e?將添加到此set中的元素。 ?
- ?????*?@return?如果此set尚未包含指定元素,則返回true。 ?
- ?????*/ ??
- ???? public ? boolean ?add(E?e)?{??
- ???? return ?map.put(e,?PRESENT)== null ;??
- ????}??
- ??
- ???? /** ?
- ?????*?如果指定元素存在于此set中,則將其移除。 ?
- ?????*?更確切地講,如果此set包含一個滿足(o==null???e==null?:?o.equals(e))的元素e, ?
- ?????*?則將其移除。如果此set已包含該元素,則返回true ?
- ?????*?(或者:如果此set因調用而發生更改,則返回true)。(一旦調用返回,則此set不再包含該元素)。 ?
- ?????* ?
- ?????*?底層實際調用HashMap的remove方法刪除指定Entry。 ?
- ?????*?@param?o?如果存在于此set中則需要將其移除的對象。 ?
- ?????*?@return?如果set包含指定元素,則返回true。 ?
- ?????*/ ??
- ???? public ? boolean ?remove(Object?o)?{??
- ???? return ?map.remove(o)==PRESENT;??
- ????}??
- ??
- ???? /** ?
- ?????*?從此set中移除所有元素。此調用返回后,該set將為空。 ?
- ?????* ?
- ?????*?底層實際調用HashMap的clear方法清空Entry中所有元素。 ?
- ?????*/ ??
- ???? public ? void ?clear()?{??
- ????map.clear();??
- ????}??
- ??
- ???? /** ?
- ?????*?返回此HashSet實例的淺表副本:并沒有復制這些元素本身。 ?
- ?????* ?
- <span
發表評論
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

評論