以下のコードを検討してください。
HashSet hs = new HashSet();
hs.add("hi"); -- (1)
hs.add("hi"); -- (2)
HashSet
は重複を許可しないので、hs.size()
は1を与え、1つの要素だけが格納されます。
重複した要素を追加するのかどうか、それが前の要素を置き換えるのか、それとも単に追加しないのかを知りたいのですが。
また、同じ場合にHashMap
を使用するとどうなりますか?
最初に知っておく必要があるのは、HashSet
がSet
のように振る舞うということです。つまり、あなたはオブジェクトを直接HashSet
に追加し、重複を含むことはできません。値を直接HashSet
に直接追加するだけです。
ただし、HashMap
はMap
型です。つまり、エントリを追加するたびに、キーと値のペアが追加されます。
HashMap
では、重複した値を持つことはできますが、重複するキーを持つことはできません。 HashMap
では、新しいエントリが古いエントリを置き換えます。最新のエントリはHashMap
にあります。
HashMapとHashSetの間のリンクを理解する:
HashMap
は重複キーを持つことができません。舞台裏でHashSet
はHashMap
を使います。
任意のオブジェクトをHashSet
に追加しようとすると、このエントリは実際にはHashMap
のキーとして格納されます - HashMap
の裏で使用されるものと同じHashSet
。この基礎となるHashMap
はキーと値のペアを必要とするため、ダミーの値が生成されます。
同じHashSet
に別の複製オブジェクトを挿入しようとすると、その下にあるHashMap
にキーとしてそれを挿入しようとします。ただし、HashMap
は重複をサポートしません。したがって、HashSet
は、その型の値を1つだけ持つことになります。副次的な注意として、重複するキーごとに、HashSetのエントリに対して生成された値はランダムまたはダミーの値なので、キーはまったく置き換えられません。キーを削除して同じキー(ダミーの値は同じ)を追加してもまったく意味がないため、無視されます。
要約:
HashMap
では、values
を重複させることができますが、keys
はできません。 HashSet
に重複を含めることはできません。
オブジェクトの追加が正常に完了したかどうかを確認するには、.add()
を呼び出したときに返されるboolean
の値を確認し、それがtrue
またはfalse
を返すかどうかを確認します。 true
が返された場合は挿入されました。
docs はこれに関してはっきりしています:HashSet.add
はを置き換えません:
指定された要素がまだ存在しない場合は、このセットに追加します。より正式には、(e == null?e2 == null:e.equals(e2))のように、このセットに要素e2が含まれていない場合は、指定された要素eをこのセットに追加します。 このセットにすでに要素が含まれている場合、呼び出しはそのセットを変更せずにfalseを返します。
しかし HashMap.put
はを置き換えます。
マップに以前にキーのマッピングが含まれていた場合は、古い値が置き換えられます。
HashSetの場合は、置き換えられません。
ドキュメントから:
http://docs.Oracle.com/javase/6/docs/api/Java/util/HashSet.html#add(E )
"指定された要素がまだ存在しない場合、このセットに追加します。より正式には、このセットに要素e2が含まれていない場合、指定された要素eをこのセットに追加します。(e == null?e2 == null:e.equals(このセットにすでに要素が含まれている場合、呼び出しはそのセットを変更せずにfalseを返します。 "
私が間違っている場合でも訂正してください、しかしあなたが得ているのは文字列で、 "Hi" == "Hi"が必ずしも正しいというわけではないということです(必ずしも同じオブジェクトではないので)。
1という答えが得られるのは、JVMが可能な場合は文字列オブジェクトを再利用するためです。この場合、JVMは文字列オブジェクトを再利用しているため、Hashmap/Hashset内の項目を上書きしています。
しかし、この動作は保証されていません(同じ値 "Hi"を持つ異なる文字列オブジェクトになる可能性があるため)。表示される動作は、JVMの最適化によるものです。
別の言い方をすれば、キーがすでに存在するHashMapにキーと値のペアを挿入すると(ある意味ではhashvalue()は同じ値を与えますが、und equal()は真ですが、2つのオブジェクトはいくつかの点で異なります。キーは置き換えられませんが、値は上書きされます。このキーは単にhashvalue()を取得し、それを使ってテーブル内の値を見つけるために使用されます。 HashSetはHashMapのキーを使用し、結果として(ユーザにとって)重要ではない任意の値を設定するので、セットの要素も置き換えられません。
HashMap
基本的にはEntry
が含まれ、その後にKey(Object)
とValue(Object)
が含まれます内部的にはHashSet
はHashMap
とHashMap
は既にあなたが指摘したように値を置き換えます。それは本当にキーを置き換えます???いいえ..そしてそれがここでのトリックです。 HashMap
は基になるHashMap
のキーとしてその値を保持し、valueは単なるダミーオブジェクトです。HashMapに同じ値を再挿入しようとした場合(基になるMapのキー)。ダミーの値を置き換えます。キー(HashSetの値)ではありません。
以下のHashSetクラスのコードを見てください。
public boolean [More ...] add(E e) {
return map.put(e, PRESENT)==null;
}
ここでeはHashSetの値ですが、基礎となるmap.andのキーは置き換えられません。私が混乱を解消できることを願っています。
HashSetはHashMapによってバックアップされるので、最初にHashマップのputメソッドをチェックする必要があります。