2011-08-11 9 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)); 

が含まれている誰かが、なぜこのコードの出力はfalseを説明できますか?さらに、このコードはUserのequalsメソッドを呼び出すことさえしません。しかし、HashSetとHashMapのソースによると、それを呼び出す必要があります。 Userのメソッドequalsは、単にユーザーの名前でequalsを呼び出します。メソッドhashCodeユーザーの名前のハッシュコードを返します

+0

(ハッシュ衝突ではなく)2つの項目が実際に等しいことを確認するために、equalsを呼び出します? –

+0

Jon Skeetを引用するには "ハッシュセット内のオブジェクトは不変であるか、ハッシュセット(またはハッシュマップ)で使用された後にそれらを変更しないで規律を守る必要があります。 - http://stackoverflow.com/questions/4718009/mutable-objects-and-hashcode – Qwerky

答えて

13

ハッシュコードのメソッドがnameフィールドに基づいていて、オブジェクトを追加した後に変更すると、2番目のcontainsチェックで新しいハッシュ値が使用され、見つからないあなたが探していたオブジェクト。これは、HashSetがハッシュコードで最初に検索されるため、その検索が失敗した場合にはequalsと呼ばれることはありません。

あなたはequalsをオーバーライドしていなかった(そのため、デフォルトの参照の等価を使用した)場合には、これがうまくいく唯一の方法がありあなたは幸運と二つのオブジェクトのハッシュコードは同じでした。しかしこれは実際にはシナリオであり、あなたはそれに頼るべきではありません。

は、その変更によってハッシュコードも変更される場合は、HashSetに追加したオブジェクトを更新する必要があります。

+0

これは、ハッシュセットに追加されたuのコピーですか?それ以外の場合は、名前セットのオブジェクトもname3を持つと思います。 – Ced

9

新しいUserには異なるハッシュコードがあるため、HashSetはそれが等しくないことを認識します。

ハッシュセットは、ハッシュコードに従ってアイテムを格納します。それは同じハッシュコードでアイテムを見つけた場合
HashSetのは、あなたが `User.equals()`メソッドを実装しました

+1

実際、hashCodeが等しい場合にのみ、equalsが呼び出されます。つまり、hashCodeを変更するUserを更新すると、hashCodeに関連付けられたEntryを含む入れ子配列は更新されません。したがって、この配列を反復処理すると、同じhashCodeを持つエントリは返されません。 hashCodeが常に0を返すようにしなければならない) – user12384512

+3

正しい。一般に、可変オブジェクトをHashSetに入れるのは悪い考えです。 'hashCode()'が '0'を返すようにすると、HashSetのすべてのパフォーマンス上の利点が失われ、おそらく取得できる最も遅いコレクションになります。 – SLaks

+0

私はこれが単なる例であることを知っています – user12384512