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已經添加了幾個成員后,修改一個成員的實例變量,會得到里面有相同的成員,因此是不對的。

 

但是,對最后一行,不能准確訪問成員這個。有點疑問,待解決。

package Test01;

import java.util.HashSet; import java.util.Iterator; class mutClass{ public int count; public mutClass(int count) { this.count =count; } public boolean equals(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 int hashcode() { return this.count; } public String toString() { return "試試mutClass[count=" + count + "]"; } } public class TestHashSet { @SuppressWarnings("unchecked") public static void main(String[] args){ HashSet testHashSet =new HashSet(); 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; /* testHashSet.remove(new mutClass(3)); testHashSet.remove(b); //與上一行的區別 */ 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 找到他的存儲位置,又能維護添加成員的順序,內部靠一個鏈表實現,迭代訪問集合時有很好的性能。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM