HASHSET原理
?http://streamlet77.iteye.com/blog/916854
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的源代碼如下:
Java代碼
?? 1. public class HashSet<E>?
?? 2.???? extends AbstractSet<E>?
?? 3.???? implements Set<E>, Cloneable, java.io.Serializable?
?? 4. {?
?? 5.???? static final long serialVersionUID = -5024744406713321676L;?
?? 6.??
?? 7.???? // 底層使用HashMap來保存HashSet中所有元素。?
?? 8.???? private transient HashMap<E,Object> map;?
?? 9.??????
? 10.???? // 定義一個虛擬的Object對象作為HashMap的value,將此對象定義為static final。?
? 11.???? private static final Object PRESENT = new Object();?
? 12.??
? 13.???? /**
? 14.????? * 默認的無參構造器,構造一個空的HashSet。
? 15.????? *?
? 16.????? * 實際底層會初始化一個空的HashMap,并使用默認初始容量為16和加載因子0.75。
? 17.????? */?
? 18.???? public HashSet() {?
? 19.???? map = new HashMap<E,Object>();?
? 20.???? }?
? 21.??
? 22.???? /**
? 23.????? * 構造一個包含指定collection中的元素的新set。
? 24.????? *
? 25.????? * 實際底層使用默認的加載因子0.75和足以包含指定
? 26.????? * collection中所有元素的初始容量來創建一個HashMap。
? 27.????? * @param c 其中的元素將存放在此set中的collection。
? 28.????? */?
? 29.???? public HashSet(Collection<? extends E> c) {?
? 30.???? map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));?
? 31.???? addAll(c);?
? 32.???? }?
? 33.??
? 34.???? /**
? 35.????? * 以指定的initialCapacity和loadFactor構造一個空的HashSet。
? 36.????? *
? 37.????? * 實際底層以相應的參數構造一個空的HashMap。
? 38.????? * @param initialCapacity 初始容量。
? 39.????? * @param loadFactor 加載因子。
? 40.????? */?
? 41.???? public HashSet(int initialCapacity, float loadFactor) {?
? 42.???? map = new HashMap<E,Object>(initialCapacity, loadFactor);?
? 43.???? }?
? 44.??
? 45.???? /**
? 46.????? * 以指定的initialCapacity構造一個空的HashSet。
? 47.????? *
? 48.????? * 實際底層以相應的參數及加載因子loadFactor為0.75構造一個空的HashMap。
? 49.????? * @param initialCapacity 初始容量。
? 50.????? */?
? 51.???? public HashSet(int initialCapacity) {?
? 52.???? map = new HashMap<E,Object>(initialCapacity);?
? 53.???? }?
? 54.??
? 55.???? /**
? 56.????? * 以指定的initialCapacity和loadFactor構造一個新的空鏈接哈希集合。
? 57.????? * 此構造函數為包訪問權限,不對外公開,實際只是是對LinkedHashSet的支持。
? 58.????? *
? 59.????? * 實際底層會以指定的參數構造一個空LinkedHashMap實例來實現。
? 60.????? * @param initialCapacity 初始容量。
? 61.????? * @param loadFactor 加載因子。
? 62.????? * @param dummy 標記。
? 63.????? */?
? 64.???? HashSet(int initialCapacity, float loadFactor, boolean dummy) {?
? 65.???? map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);?
? 66.???? }?
? 67.??
? 68.???? /**
? 69.????? * 返回對此set中元素進行迭代的迭代器。返回元素的順序并不是特定的。
? 70.????? *?
? 71.????? * 底層實際調用底層HashMap的keySet來返回所有的key。
? 72.????? * 可見HashSet中的元素,只是存放在了底層HashMap的key上,
? 73.????? * value使用一個static final的Object對象標識。
? 74.????? * @return 對此set中元素進行迭代的Iterator。
? 75.????? */?
? 76.???? public Iterator<E> iterator() {?
? 77.???? return map.keySet().iterator();?
? 78.???? }?
? 79.??
? 80.???? /**
? 81.????? * 返回此set中的元素的數量(set的容量)。
? 82.????? *
? 83.????? * 底層實際調用HashMap的size()方法返回Entry的數量,就得到該Set中元素的個數。
? 84.????? * @return 此set中的元素的數量(set的容量)。
? 85.????? */?
? 86.???? public int size() {?
? 87.???? return map.size();?
? 88.???? }?
? 89.??
? 90.???? /**
? 91.????? * 如果此set不包含任何元素,則返回true。
? 92.????? *
? 93.????? * 底層實際調用HashMap的isEmpty()判斷該HashSet是否為空。
? 94.????? * @return 如果此set不包含任何元素,則返回true。
? 95.????? */?
? 96.???? public boolean isEmpty() {?
? 97.???? return map.isEmpty();?
? 98.???? }?
? 99.??
100.???? /**
101.????? * 如果此set包含指定元素,則返回true。
102.????? * 更確切地講,當且僅當此set包含一個滿足(o==null ? e==null : o.equals(e))
103.????? * 的e元素時,返回true。
104.????? *
105.????? * 底層實際調用HashMap的containsKey判斷是否包含指定key。
106.????? * @param o 在此set中的存在已得到測試的元素。
107.????? * @return 如果此set包含指定元素,則返回true。
108.????? */?
109.???? public boolean contains(Object o) {?
110.???? return map.containsKey(o);?
111.???? }?
112.??
113.???? /**
114.????? * 如果此set中尚未包含指定元素,則添加指定元素。
115.????? * 更確切地講,如果此 set 沒有包含滿足(e==null ? e2==null : e.equals(e2))
116.????? * 的元素e2,則向此set 添加指定的元素e。
117.????? * 如果此set已包含該元素,則該調用不更改set并返回false。
118.????? *
119.????? * 底層實際將將該元素作為key放入HashMap。
120.????? * 由于HashMap的put()方法添加key-value對時,當新放入HashMap的Entry中key
121.????? * 與集合中原有Entry的key相同(hashCode()返回值相等,通過equals比較也返回true),
122.????? * 新添加的Entry的value會將覆蓋原來Entry的value,但key不會有任何改變,
123.????? * 因此如果向HashSet中添加一個已經存在的元素時,新添加的集合元素將不會被放入HashMap中,
124.????? * 原來的元素也不會有任何改變,這也就滿足了Set中元素不重復的特性。
125.????? * @param e 將添加到此set中的元素。
126.????? * @return 如果此set尚未包含指定元素,則返回true。
127.????? */?
128.???? public boolean add(E e) {?
129.???? return map.put(e, PRESENT)==null;?
130.???? }?
131.??
132.???? /**
133.????? * 如果指定元素存在于此set中,則將其移除。
134.????? * 更確切地講,如果此set包含一個滿足(o==null ? e==null : o.equals(e))的元素e,
135.????? * 則將其移除。如果此set已包含該元素,則返回true
136.????? * (或者:如果此set因調用而發生更改,則返回true)。(一旦調用返回,則此set不再包含該元素)。
137.????? *
138.????? * 底層實際調用HashMap的remove方法刪除指定Entry。
139.????? * @param o 如果存在于此set中則需要將其移除的對象。
140.????? * @return 如果set包含指定元素,則返回true。
141.????? */?
142.???? public boolean remove(Object o) {?
143.???? return map.remove(o)==PRESENT;?
144.???? }?
145.??
146.???? /**
147.????? * 從此set中移除所有元素。此調用返回后,該set將為空。
148.????? *
149.????? * 底層實際調用HashMap的clear方法清空Entry中所有元素。
150.????? */?
151.???? public void clear() {?
152.???? map.clear();?
153.???? }?
154.??
155.???? /**
156.????? * 返回此HashSet實例的淺表副本:并沒有復制這些元素本身。
157.????? *?
?
而hashmap,對于已存在的元素,新的會覆蓋舊的
總結
- 上一篇: resource busy and ac
- 下一篇: oracle 数组定义