2012-04-14 2 views
2

VをKという名前の単一の属性とそのゲッターとセッターであるクラスとします。マップキーは不変であることを想定しているので、マップキーとして使用されるオブジェクトの変更

V v = new V(); 
v.setK("a"); 
HashMap<K,V> map = new HashMap<K,V>(); 
map.put(v.getk(),v); 
v.setK("b"); 

私の知る限りでは、これが問題のいくつかの種類を起こす必要があります。私がしなければ起こることになっているもの

。ここで何が起こるでしょうか?

編集:キーは文字列ではなく、下記のように変更可能なオブジェクトであると考えてください。

+1

問題があるシナリオは、あなたがK [ey]をオブジェクト化するときに複雑なオブジェクトです。たとえば、属性Aを含み、KはA値に基づいて独自のhashCodeを計算します。その場合、Kを地図のキーとして使用した後にAが変更された場合、Map契約に違反します。 JavaDocからの引用:変更可能なオブジェクトがマップキーとして使用されている場合は、十分な注意が必要です。オブジェクトがマップ内のキーである間に等価比較に影響するようにオブジェクトの値が変更された場合、マップの動作は指定されません。 –

+0

もちろん、私の悪い。私はいつもこの事件を意味していました。文字列をキーとして使うのは悪い例でした。私は質問を編集しています、ありがとう。 – bluehallu

答えて

5

引用を実行しようとしていない:

マップ可能なオブジェクトをマップキーとして使用する場合は、十分な注意が必要です。オブジェクトがマップ内のキーである間に等価比較に影響するようにオブジェクトの値が変更された場合、マップの動作は指定されません。

キーを(「hashCode」/「equals」を変更する方法で)変更しないでください。試してみると、間違いなく非常に長くてひどいデバッグがあります。

これは図書館の本を交換するようなものです。指数は信頼できなくなった。あなたは "Bradbury"を検索しますが、 "Simak"を探します。

+0

クラスが 'equals()' *をオーバーライドし、*属性 'k'がクラスによって使用されている場合にのみ、あなたの観測結果が適用されることを付け加えるべきです。 (すなわち、 'k'の値が' equals() 'に影響を及ぼす場合) – Bohemian

+0

@Bohemianあいまいさを避けるために丸括弧でフレーズを追加しました。 –

1

あなたはV上のゲッターによる値の戻りを変更したので、あなたは、それがエントリを見つけられないでしょうv.getk()を使用してマップを検索しようとしていた場合。

換言すれば、地図ISN」あなたのvオブジェクトに起こることと魔法のように同期しています - put()に与えられた値を使用し続けます。

+0

* "...マップは魔法のように同期されているわけではありません..." * - その1つの理由は、マップがキーが変更されたことを知る方法がないことです。 –

1

v.setK()を呼び出すと、HashMapのキーは変更されません。したがって、Vオブジェクトに間違った情報が含まれるだけです。

+0

したがって、put()鍵を握ってそれを保管していますか? – bluehallu

+0

@Hallucynogenyc:いいえ、まったく... HashMapを使用しているので、単に識別子としてHashCodeを使用します。 –

+0

Mmmm ...キーのhashCodeしか格納されていない場合、どのように元のキーを取得できますか? – bluehallu

1

として使用されているオブジェクトをに変更するなど、マップキーを変更していない場合、この質問のタイトルが誤解を招くことがあります。 map.put(x, y)と言うとき、マップエントリを作成して、2つの独立した値:キーを集計します。キーの由来は、マップからは見えませんが、それはちょうど2つのオブジェクトです。したがって、マップエントリ("a", v)を作成した後、vの状態を変更しただけで、マップエントリのキー「a」に影響する可能性はありません。一方で、あなたは

public class K { 
    private String s; 
    public K(String s) { this.s = s; } 
    public void setS(String s) { this.s = s; } 
    public boolean equals(Object o) { return ((K)o).s.equals(this.s); } 
    public int hashCode() { return s.hashCode(); } 

}

のように、自分自身の意思のオブジェクトKを持っていたし、今は

final K k = new K("a"); 
map.put(k, v); 
k.setS("b"); 
map.get(k); 

を行い、なら、あなたは、問題に直面するだろう - あなたをは、マップキーとして使用されるオブジェクトを変更しました。

+0

申し訳ありませんが、あなたの質問を間違って読んでいます。私の答えは問題に合わない。私はそれを変更します。 –

+0

私は私の答えを根本的に変えました。 –

1
V v = new V(); 
v.setK("a"); 
HashMap<K,V> map = new HashMap<K,V>(); 
map.put(v.getk(),v); 

//Nothing will change in the hashmap with this step 
v.setK("b"); 

しかし、マップからオブジェクトVをフェッチするときに問題があります。 map.get(v.getk())を呼び出すと、マップの値がオブジェクト "a"にマップされるため、nullが返されます。しかし、このStringので、「」あなたはいつもまたは

V v = new V(); 
v.setK("a"); 
map.get(v.getK()); 

PSによってマップからこのオブジェクトを取得することができます間である:私は「地図」インターフェースのJavaDocからこの

関連する問題