2009-07-02 6 views
10

Java Set <>(または、その点については<>のキー)に含まれるオブジェクトがある場合は、 (hashCode()equals()compareTo()等を介して)同一性または関係を決定するために使用されるコレクションの操作のために指定されていない動作を引き起こすことなく、変更することはできないのですか? (編集:this other questionで示唆したように)Java Set内のオブジェクトの可変フィールド

(言い換えれば、これらのフィールドは不変であるべきか、あなたは、コレクションから削除するオブジェクトを要求すべきである、そしてその後、再挿入、変更。)

ザ・私が尋ねる理由は、私はHibernate Annotations reference guideを読んでいたということであり、そこHashSet<Toy>があるが、Toyクラスは変更可能であり、hashCode()計算にも使用されているフィールドnameserialを持っている例があります...赤い旗が私の中に消えました私はちょうど私がそれの意味を理解していることを確認したかった。正しい

答えて

7

Javadocは

注意を言います。一連の動作は、オブジェクトの値は、オブジェクトが 集合の要素であるが、比較に等しい に影響を与えるように変化 ある場合、指定 ありません。この禁止の特別な場合 は、要素として 自体を含むように設定するための許容 ないことです。

これは、セット内で可変オブジェクトを使用でき、それらを変更することもできます。変更がアイテムを見つける方法に影響しないことを確認するだけです。 HashSetの場合は、計算に使用するフィールドを変更しないでください。hashCode() HashSetの/ HashMapので

3

、それはマップエントリを見つけるいくつかの問題を引き起こす可能性があります。公式には動作は未定義であるため、ハッシュマップに追加するか、ハッシュマップのキーとして追加する場合は変更しないでください。

1

はい、悪いことが起こります。 変更可能なオブジェクトを設定 要素として使用されている場合には細心の注意を払わなければならない:Setため

// Given that the Toy class has a mutable field called 'name' which is used 
// in equals() and hashCode(): 
Set<Toy> toys = new HashSet<Toy>(); 
Toy toy = new Toy("Fire engine", ToyType.WHEELED_VEHICLE, Color.RED); 
toys.add(toy); 
System.out.println(toys.contains(toy)); // true 
toy.setName("Fast truck"); 
System.out.println(toys.contains(toy)); // false 
+0

私はちょうどこれが本当に悪い例であることを知った。私はまだ参照を保持していたので、最後のcontains()は実際にtrueを返します。 HashMapsは別の問題ですが、3日間の週末はほとんど終了しているので、例を掘り起こしたくありません。 –

+0

heh、戻ってきたら何かを投稿してください - 楽しみにしています。 –

+0

もう一度、HashSetがHashMapをバッキングとして使用しているのを忘れました。バッキングHashMapはハッシュコードを使用してバケット内の要素に対してequals()をチェックする前にバケットにジャンプし、要素を変更すると間違ったバケットにジャンプして要素を見つけられません。 –

0

、あなたcompareTo()操作の結果を変更するために含まれるオブジェクトを変異させることができ - 相対比較がオブジェクトを見つけるために使用されていません。しかし、TreeSet/TreeMapの内部では致命的になります。

またのIdentityHashMapの内側にあるオブジェクトを変異させることができます - オブジェクトのアイデンティティ以外何も内容を検索するために使用されていません。

あなたはこれらの資格でこれらの事を行うことができるにもかかわらず、彼らはあなたのコードをより脆く。誰かが後でTreeSetに変更したい場合や、その変更可能なフィールドをhashCode/equalityテストに追加する場合はどうなりますか?