Додавання дублюючого значення до HashSet / HashMap замінює попереднє значення


137

Врахуйте наведений нижче код:

HashSet hs = new HashSet();
hs.add("hi"); -- (1)
hs.add("hi"); -- (2)

hs.size()дасть 1, оскільки HashSetне дозволяє дублікати, тому буде збережено лише один елемент.

Я хочу знати, якщо ми додаємо повторюваний елемент, то він замінює попередній елемент чи він просто не додає його?

Також, що буде з використанням одного HashMapі того ж випадку?

Відповіді:


247

У випадку з HashMapцим воно замінює старе значення новим.

У випадку HashSet, елемент не вставляється.


1
Не впевнений, чого мені не вистачає, але, здається, вихідний код вказує інакше? Я бачу, що вони не проводять перевірку резервної копії, HashMapщоб побачити, чи keyіснує вже перед тим, як викликати putрезервну копію map?
mystarrocks

10
@mystarrocks: Ключ - це елемент Set, який ніколи не замінюється put()операцією.
Кеппіль

1
ах я це зараз зрозумію. Я зрозумів, що ключ є елементом Set, але тільки що зрозумів, що put()лише перекриє значення, а не ключ. У цьому випадку це те саме значення, яке знову кладемо поруч із ключем, що може бути, а може і не бути кращим, ніж перевірка наявності ключа та введення. Так чи інакше, я розумію, як це працює.
mystarrocks

Просто цікаво, чому HashMap і HashSet вирішили бути такими?
Хелін Ван

@HelinWang: Я не думаю, що це було заплановано, я думаю, що це лише ефект від HashSetреалізації у формі HashMap. Але важко знати, якщо ви не є одним із розробників класів.
Keppil

47

Перше, що вам потрібно знати, це те, що HashSetдіє як a Set, а це означає, що ви додаєте свій об'єкт безпосередньо до HashSetі він не може містити дублікатів. Ви просто додаєте свою вартість безпосередньо в HashSet.

Однак, HashMapце Mapтип. Це означає, що кожного разу, коли ви додаєте запис, ви додаєте пару ключ-значення.

У HashMapвас можуть бути повторювані значення, але не дублюючі ключі. У HashMapновому записі замінить старий. Останній запис буде в HashMap.

Розуміння зв'язку між HashMap і HashSet:

Пам'ятайте, HashMapне можна мати дублюючі ключі. За сценою HashSetвикористовується а HashMap.

При спробі додати будь-який об'єкт до а HashSet, ця запис насправді зберігається як ключ у HashMap- тому самому, HashMapщо використовується поза сценою HashSet. Оскільки для цього лежить HashMapпотреба пари ключ-значення, для нас формується фіктивне значення.

Тепер, коли ви спробуєте вставити ще один дублікат об'єкта в той самий HashSet, він знову буде намагатися вставити його як ключ у HashMapлежачому під ним. Однак HashMapне підтримує дублікати. Отже, HashSetвсе одно буде мати лише одне значення цього типу. Як бічна примітка, для кожного повторюваного ключа, оскільки значення, створене для нашого запису в HashSet, є деяким випадковим / фіктивним значенням, ключ взагалі не замінюється. це буде ігноруватися, оскільки видалення ключа та додавання назад того самого ключа (фіктивне значення те саме) взагалі не мали б сенсу.

Підсумок:

HashMapдозволяє дублювати values, але ні keys. HashSetне може містити дублікатів.

Щоб грати з тим, успішно завершено додавання об'єкта чи ні, ви можете перевірити booleanзначення, яке повертається під час дзвінка, .add() і побачити, повертається він trueчи false. Якщо він повернувся true, його вставили.


HashMap allows duplicate valuesHashMap замінює старе значення новим.
Alex78191

20

Ці документи досить ясно з цього питання : HashSet.add НЕ замінити:

Додає вказаний елемент до цього набору, якщо його вже немає. Більш формально додає вказаний елемент e до цього набору, якщо цей набір не містить елемента e2, такого що (e == null? E2 == null: e.equals (e2)). Якщо цей набір вже містить елемент, виклик залишає набір незмінним і повертає помилковим.

Але буде замінити:HashMap.put

Якщо раніше карта містила відображення ключа, старе значення замінюється.


4

Це справа HashSet, він НЕ замінює його.

З документів:

http://docs.oracle.com/javase/6/docs/api/java/util/HashSet.html#add(E )

"Додає вказаний елемент до цього набору, якщо його вже немає. Більш формально додає вказаний елемент e до цього набору, якщо цей набір не містить елемента e2 такого, що (e == null? E2 == null: e.equals ( e2)). Якщо цей набір вже містить елемент, виклик залишає набір незмінним і повертає помилковим. "


1

Виправте мене, якщо я помиляюся, але те, що ви отримуєте, - це те, що з рядками "Привіт" == "Привіт" не завжди виходить справжнім (тому що вони не обов'язково є одним і тим же об'єктом).

Причина, чому ви отримуєте відповідь 1, полягає в тому, що JVM повторно використовує рядкові об'єкти, де це можливо. У цьому випадку JVM повторно використовує рядовий об'єкт і, таким чином, перезаписує елемент у Hashmap / Hashset.

Але вам не гарантується така поведінка (тому що це може бути інший рядковий об'єкт, який має те саме значення "Привіт"). Поведінка, яку ви бачите, саме завдяки оптимізації JVM.


0

Вам потрібно спочатку перевірити метод put на карті Hash, оскільки HashSet створив резервну копію HashMap

  1. Коли ви додасте значення, що повторюється, скажіть рядок "Один" в HashSet,
  2. Запис ("one", PRESENT) буде вставлений у Hashmap (для всіх значень, доданих у набір, значення буде "PRESENT", яке, якщо типу типу Object)
  3. Hashmap додає запис у Map і повертає значення, яке в даному випадку є "ПРИСТУПНО" або null, якщо Entry там немає.
  4. Метод add Hashset потім повертає true, якщо повернене значення з Hashmap дорівнює нулю, інакше false, що означає, що запис вже існує ...

0

Якщо сказати інакше: Коли ви вставляєте пару ключів-значень у HashMap, де ключ вже існує (у певному значенні hashvalue () дає однакове значення und рівне (), це правда, але два об'єкти все ще можуть відрізнятися кількома способами ), ключ не замінюється, але значення перезаписується. Ключ просто використовується, щоб отримати хевалю () і знайти в ньому значення в таблиці. Оскільки HashSet використовує ключі HashMap і встановлює довільні значення, які насправді не мають значення для користувача, в результаті елементи Набору також не замінюються.


0

HashMapв основному містить, Entryщо згодом містить Key(Object)і. Value(Object)Внутрішнє значення HashSetє HashMapі HashMapзаміняють значення, як деякі з вас уже вказували .. Але це дійсно замінює ключі ??? Ні .. І в цьому полягає трюк. HashMapзберігає своє значення як ключове в нижньомуHashMap а значення є лише манекеновим об'єктом. Якщо ви намагаєтесь знову встановити таке ж значення в HashMap (Ключ в базовій карті). Він просто замінює фіктивне значення, а не ключ (значення для HashSet).

Подивіться код нижче для класу HashSet:

public boolean  [More ...] add(E e) {

   return map.put(e, PRESENT)==null;
}

Тут e - значення для HashSet, але ключ для основної map.and ключ ніколи не замінюється. Сподіваюся, я зміг усунути плутанину.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.