1. HashSet概述
HashSet實(shí)現(xiàn)Set接口,由哈希表(實(shí)際上是一個(gè)HashMap實(shí)例)支持,。它不保證set 的迭代順序,;特別是它不保證該順序恒久不變,。此類(lèi)允許使用null元素,。
2. HashSet的實(shí)現(xiàn)
如果不等,則添加到該數(shù)組索引對(duì)應(yīng)的鏈表中,。
------------------------------------------------------------------------------------------
Set的實(shí)現(xiàn)類(lèi)的集合對(duì)象中不能夠有重復(fù)元素,,HashSet也一樣他是使用了一種標(biāo)識(shí)來(lái)確定元素的不重復(fù),HashSet用一種算法來(lái)保證
HashSet中的元素是不重復(fù)的,, HashSet采用哈希算法,,底層用數(shù)組存儲(chǔ)數(shù)據(jù)。默認(rèn)初始化容量16,,加載因子0.75
Object類(lèi)中的hashCode()的方法是所有子類(lèi)都會(huì)繼承這個(gè)方法,,這個(gè)方法會(huì)用Hash算法算出一個(gè)Hash(哈希)碼值返回,HashSet
會(huì)用Hash碼值去和數(shù)組長(zhǎng)度取模,,
模(這個(gè)模就是對(duì)象要存放在數(shù)組中的位置)相同時(shí)才會(huì)判斷數(shù)組中的元素和要加入的對(duì)象的內(nèi)容是否相同,,如果不同才會(huì)添加進(jìn)去。
Hash算法是一種散列算法,。
Set hs=new HashSet();
hs.add(o);
|
o.hashCode();
|
o%當(dāng)前總?cè)萘?nbsp; (0--15)
|
| 不發(fā)生沖突
是否發(fā)生沖突-----------------直接存放
|
| 發(fā)生沖突
| 假(不相等)
o1.equals(o2)-------------------找一個(gè)空位添加
|
| 是(相等)
不添加
覆蓋hashCode()方法的原則:
1,、一定要讓那些我們認(rèn)為相同的對(duì)象返回相同的hashCode值
2、盡量讓那些我們認(rèn)為不同的對(duì)象返回不同的hashCode值,,否則,,就會(huì)增加沖突的概率。
3,、盡量的讓hashCode值散列開(kāi)(兩值用異或運(yùn)算可使結(jié)果的范圍更廣)
HashSet
的實(shí)現(xiàn)比較簡(jiǎn)單,,相關(guān)HashSet的操作,基本上都是直接調(diào)用底層HashMap的相關(guān)方法來(lái)完成,,我們應(yīng)該為保存到HashSet中的對(duì)象覆蓋
hashCode()和equals(),,因?yàn)樵賹?duì)象加入到HashSet中時(shí),會(huì)首先調(diào)用hashCode方法計(jì)算出對(duì)象的hash值,,接著根據(jù)此
hash值調(diào)用HashMap中的hash方法,得到的值& (length-1)得到該對(duì)象在hashMap的transient
Entry[]
table中的保存位置的索引,,接著找到數(shù)組中該索引位置保存的對(duì)象,,并調(diào)用equals方法比較這兩個(gè)對(duì)象是否相等,如果相等則不添加,,注意:所以要存
入HashSet的集合對(duì)象中的自定義類(lèi)必須覆蓋hashCode(),equals()兩個(gè)方法,,才能保證集合中元素不重復(fù),。在覆蓋equals()和
hashCode()方法時(shí),
要使相同對(duì)象的hashCode()方法返回相同值,,覆蓋equals()方法再判斷其內(nèi)容,。為了保證效率,所以在覆蓋hashCode()方法時(shí),,
也要盡量使不同對(duì)象盡量返回不同的Hash碼值,。
如果數(shù)組中的元素和要加入的對(duì)象的hashCode()返回了相同的Hash值(相同對(duì)象),才會(huì)用equals()方法來(lái)判斷兩個(gè)對(duì)象的內(nèi)容是否相同。
------------------------------------------------------------------------------------------
HashSet的源代碼如下:
- public class HashSet<E>
- extends AbstractSet<E>
- implements Set<E>, Cloneable, java.io.Serializable
- {
- static final long serialVersionUID = -5024744406713321676L;
-
-
- private transient HashMap<E,Object> map;
-
-
- private static final Object PRESENT = new Object();
-
-
-
-
-
-
- public HashSet() {
- map = new HashMap<E,Object>();
- }
-
-
-
-
-
-
-
-
- public HashSet(Collection<? extends E> c) {
- map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));
- addAll(c);
- }
-
-
-
-
-
-
-
-
- public HashSet(int initialCapacity, float loadFactor) {
- map = new HashMap<E,Object>(initialCapacity, loadFactor);
- }
-
-
-
-
-
-
-
- public HashSet(int initialCapacity) {
- map = new HashMap<E,Object>(initialCapacity);
- }
-
-
-
-
-
-
-
-
-
-
- HashSet(int initialCapacity, float loadFactor, boolean dummy) {
- map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
- }
-
-
-
-
-
-
-
-
-
- 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);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public boolean add(E e) {
- return map.put(e, PRESENT)==null;
- }
-
-
-
-
-
-
-
-
-
-
-
- public boolean remove(Object o) {
- return map.remove(o)==PRESENT;
- }
-
-
-
-
-
-
- public void clear() {
- map.clear();
- }
-
-
-
-
-
-
- public Object clone() {
- try {
- HashSet<E> newSet = (HashSet<E>) super.clone();
- newSet.map = (HashMap<E, Object>) map.clone();
- return newSet;
- } catch (CloneNotSupportedException e) {
- throw new InternalError();
- }
- }
- }
|