天天看點

java set hashset_java Set HashSet詳解

Set集合

就像把對象随意扔進罐子裡,無法記住元素的添加順序。Set某種程度就是Collection,方法沒有不同,隻是行為稍微不同,(不允許重複元素),如果一定要往裡加兩個相同元素,添加失敗add()傳回false;

上面的Set的一些共同點,Hashset,TreeSet,EunmSet三個實作類還各有特色。

依次介紹下

Hashset

判斷Hashset 集合裡的兩個對象相等,過兩關,equal()比較相等,對象的hashcode()也相等

為什麼還得比較對象的hashcode()?

Hashset 集合收進一個對象時,會調用對象的hashcode()得到其Hashcode值來決定他的存儲位置。是以,即使是equal()比較相等的兩個對象,hashcode不同,存放在hashset裡的位置不同,依然能把這兩個對象添加成功。

注意:把對象裝進hashset時,如果要重寫equals方法,也得重寫hashcode 方法,因為equals()相等的兩對象hashcode 也是相同的。

提問:hashcode()對hashset是很重要的嗎?

答:hash算法是快速查找被檢索的對象。通過對象的hashcode定位集合裡的對象的存儲位置。定位該元素。對比下,數組是存儲一組元素最快的數組結構,數組通過索引找到它的組員,通過索引能計算元素在記憶體裡的存儲位置。

但是為嘛有了數組,還用hashset呢?數組也有局限性,索引是連續的,而且長度不可變。

hashset有了hashcode,是以能快速定位對象位置,而且任意增加對象。

重寫hashcode() 注意java.lang.Object中對hashCode的約定:

兩個對象通過equals()比較相等時,他們的hashcode 也應該是一樣的。

程式運作過程中,同一個對象多次調用hashcode方法傳回應該是一樣的。

如果根據 equals(java.lang.Object) 方法,兩個對象不相等,那麼在兩個對象中的任一對象上調用 hashCode 方法不一定會生成不同的整數結果。但是,為不相等的對象生成不同整數結果可以提高哈希表的性能。 實際上,由 Object 類定義的 hashCode 方法确實會針對不同的對象傳回不同的整數。

向hashset裡添加了一個可變對象後時,要注意:如果後面的程式修改了這個可變對象的執行個體變量時,可能會導緻他與集合裡的其他元素相同,即兩個對象equals傳回true,hashcode也相同。導緻hashSet不能正确操作那些元素。

補充了解下,可變對象:建立後,對象的屬性值可能會變,也就是說,建立後對象的hash值可能會改變。

舉例:對象MutableKey的鍵在建立時變量 i=10 j=20,哈希值是1291。然後我們改變執行個體的變量值,該對象的鍵 i 和 j 從10和20分别改變成30和40。現在Key的哈希值已經變成1931。顯然,這個對象的鍵在建立後發生了改變。是以類MutableKey是可變的。

下面代碼是hashset裡添加了一個可變對象例子,

可看出,hashset已經添加了幾個成員後,修改一個成員的執行個體變量,會得到裡面有相同的成員,是以是不對的。

但是,對最後一行,不能準确通路成員這個。有點疑問,待解決。

packageTest01;

importjava.util.HashSet;

importjava.util.Iterator;

classmutClass{

public intcount;

public mutClass(intcount) {

this.count =count;

}

public booleanequals(Object obj) {

if(this ==obj) {

return true;

}

if(obj != null && obj.getClass() == mutClass.class) {

mutClass m =(mutClass) obj;

return this.count ==m.count;

}

return false;

}

public inthashcode() {

return this.count;

}

publicString toString() {

return "試試mutClass[count=" + count + "]";

}

}

public classTestHashSet {

@SuppressWarnings("unchecked")

public static voidmain(String[] args){

HashSet testHashSet =newHashSet();

mutClass a = new mutClass(3);

mutClass b = new mutClass(1);

mutClass c = new mutClass(-9);

mutClass d = new mutClass(9);

testHashSet.add(a);

testHashSet.add(b);

testHashSet.add(c);

testHashSet.add(d);

System.out.println("第一次"+testHashSet);

Iterator iterator =testHashSet.iterator();

mutClass first =(mutClass) iterator.next();

first.count=9;

System.out.println("第二次"+testHashSet);

System.out.println(new mutClass(-9) == new mutClass(-9));

System.out.println("第四次"+testHashSet.contains(new mutClass(-9)));

}

}

hashset不能保證添加成員的順序,和自己的順序是一樣的,但是引入了一個LinkedHashSet子類,使得它能和hashset一樣,靠hashcode 找到他的存儲位置,又能維護添加成員的順序,内部靠一個連結清單實作,疊代通路集合時有很好的性能。