2011-08-11 37 views
10

關於Java HashSet的新手問題理解包含Java HashSet的方法

Set<User> s = new HashSet<User>(); 
User u = new User(); 
u.setName("name1"); 
s.add(u); 
u.setName("name3"); 
System.out.println(s.contains(u)); 

有人可以解釋爲什麼這代碼輸出錯誤的?而且這個代碼甚至不會調用User的equals方法。但根據HashSet和HashMap的來源,它必須調用它。方法等於用戶簡單地調用用戶名稱上的等於。方法hashCode返回用戶名的hashCode

+0

你執行'User.equals()'方法? –

+0

引用Jon Skeet「哈希集合中的對象應該是不可變的,或者你需要在哈希集合(或散列表)中使用哈希集合後,不要改變它們。」 - http://stackoverflow.com/questions/4718009/mutable-objects-and-hashcode – Qwerky

回答

13

如果哈希碼的方法是基於name的字段,然後在添加對象後再改變它,那麼第二個contains檢查將使用新的哈希值,並且不會查找你正在尋找的對象。這是因爲HashSet是首次使用哈希碼進行搜索,所以如果搜索失敗,他們不會打擾equals

這會工作的唯一方法是,如果你有沒有覆蓋equals(所以使用了默認引用相等)你很幸運,這兩個對象的哈希碼都是平等的。但這是一個不太可能發生的情況,你不應該依賴它。

一般來說,你應該從來沒有更新一個對象,你已經添加到HashSet後,如果該更改也將更改其哈希碼。

+0

所以它是你在哈希集中添加的副本?否則,我會認爲nameset中的對象將具有name3以及 – Ced

9

由於您的新User具有不同的哈希碼,因此HashSet知道它不相同。

HashSets根據它們的哈希碼存儲它們的項目。
HashSet中只會叫equals如果找到具有相同散列碼的項目,以確保這兩個項目實際上是相等的(而不是一個哈希碰撞)

+1

實際上,只有在hashCode相等時才調用equals。這意味着如果我更新用戶,它會更改它的hashCode,包含與其hashCodes相關聯的Entry的嵌套數組將不會更新。因此迭代這個數組不會返回具有相同hashCode的條目。如果hashCode總是返回0,應該工作) – user12384512

+3

正確。一般來說,在HashSet中放置可變對象是一個壞主意。如果你使'hashCode()'返回'0',你將失去HashSet的所有性能好處,並且最終會得到你可能獲得的最慢集合。 – SLaks

+0

我知道,這只是一個例子 – user12384512