add
のHashSet
メソッドを試していました。それが言及されている
このセットにすでに要素が含まれている場合、呼び出しはセットを変更せずにfalseを返します。
しかし、add
メソッドは内部的にHashMap
の値を保存しています
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
put
のHashMap
メソッドは、
指定された値をこのマップの指定されたキーに関連付けます。マップに以前にキーのマッピングが含まれていた場合、古い値は置き換えられます。
つまり、put
のHashMap
メソッドが古い値を置き換える場合、HashSet
add
メソッドは、要素が重複する場合にセットを変更しないままにする方法?
PRESENT
は単なるダミー値です。セットは実際にはそれを気にしません。セットdoesが気にするのは、マップのkeysです。したがって、ロジックは次のようになります。
Set.add(a):
map.put(a, PRESENT) // so far, this is just what you said
the key "a" is in the map, so...
keep the "a" key, but map its value to the PRESENT we just passed in
also, return the old value (which we'll call OLD)
look at the return value: it's OLD, != null. So return false.
さて、OLD == PRESENT
は重要ではありません。また、Map.put
はキーを変更せず、そのキーにマップされた値だけを変更することに注意してください。マップのkeysはSet
が本当に気にするものなので、Set
は変わりません。
実際、hasSet
の基本構造に何らかの変更がありました-(a, OLD)
のマッピングを(a, PRESENT)
に置き換えました。しかし、それはSet
の実装の外側からは観察できません。 (そして、たまたま、OLD == PRESENT
なので、その変更は本当の変更ではありません。).
ご覧のとおり、HashSet.add
メソッドは、値としてではなくキーとしてHashMap.put
に要素を追加します。値はキーではなくHashMap
で置き換えられます。
見る - HashMap#put
:
指定された値をこのマップの指定されたキーに関連付けます。マップに以前にキーのマッピングが含まれていた場合、古い値は置き換えられます。
キーをnew値に置き換えます。これにより、HashSet
に重複がなくなります。
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
eがキーであるため、eがすでに存在する場合、put
はnull
を返しません。したがって、add
はfalseを返します。
put
のJavaDoc:
キーに関連付けられた以前の値、またはキーのマッピングがなかった場合はnull (nullの戻り値は、マップが以前にnullをキーに関連付けていたことを示す場合もあります。)
HashMap.put()のjavadocsから、「指定された値をこのマップの指定されたキーに関連付けます。マップに以前にキーのマッピングが含まれていた場合、古い値は置き換えられます。」
したがって、マップ値が置き換えられ(HashSetクラスの定数静的フィールドであるため、同じインスタンスが置き換えられます)、マップキーはそのまま保持されます(実際にはIS Setコレクションアイテム)