Заменяет ли добавление повторяющегося значения в HashSet / HashMap предыдущее значение

137

Пожалуйста, рассмотрите следующий фрагмент кода:

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

hs.size()даст 1, поскольку HashSetне допускает дублирования, поэтому будет сохранен только один элемент.

Я хочу знать, если мы добавим дублирующий элемент, то он заменит предыдущий элемент или просто не добавит его?

Кроме того, что будет использоваться HashMapдля того же случая?

Ананд
источник

Ответы:

247

В случае HashMap, он заменяет старое значение новым.

В случае HashSet, элемент не вставлен.

Keppil
источник
1
Не уверен, что мне не хватает, но исходный код, кажется, указывает на обратное? Я вижу, что они не проверяют поддержку, HashMapчтобы увидеть, существует ли keyуже, прежде чем вызывать putподдержку map?
mystarrocks
10
@mystarrocks: ключ является элементом Set, который никогда не заменяется put()операцией.
Кеппил
1
ах я понял сейчас. Я понял, что ключ является элементом Set, но только что понял, что put()переопределит только значение, а не ключ. В этом случае это то же самое значение, которое снова ставится рядом с ключом, что может быть лучше, а не проверять, существует ли ключ и вводить его. В любом случае, я понимаю, как это работает.
mystarrocks
Просто любопытно, почему HashMap и HashSet выбирают именно так?
Хелин Ван
@HelinWang: Я не думаю, что это было запланировано, я думаю, что это просто эффект от HashSetреализации в форме HashMap. Трудно знать, хотя, если вы не являетесь одним из разработчиков классов.
Кеппил
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)). Если этот набор уже содержит элемент, вызов оставляет набор неизменным и возвращает false.

Но будет заменить:HashMap.put

Если карта ранее содержала сопоставление для ключа, старое значение заменяется.

pb2q
источник
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)). Если этот набор уже содержит элемент, вызов оставляет набор без изменений и возвращает false. "

Боб Провенчер
источник
1

Поправьте меня, если я ошибаюсь, но вы понимаете, что со строками "Hi" == "Hi" не всегда получается (потому что они не обязательно являются одним и тем же объектом).

Причина, по которой вы получаете ответ 1, заключается в том, что JVM будет повторно использовать строковые объекты, где это возможно. В этом случае JVM повторно использует строковый объект и, таким образом, перезаписывает элемент в Hashmap / Hashset.

Но вам не гарантируется такое поведение (потому что это может быть другой строковый объект с тем же значением «Привет»). Поведение, которое вы видите, просто из-за оптимизации JVM.

Ник Риппе
источник
0

Вы должны сначала проверить метод put в Hash map, так как HashMap поддерживается HashMap

  1. Когда вы добавляете повторяющееся значение, говорите String «One» в HashSet,
  2. Запись ("one", PRESENT) будет вставлена ​​в Hashmap (для всех значений, добавленных в set, значение будет "PRESENT", которое, если имеет тип Object)
  3. Hashmap добавляет запись в Map и возвращает значение, которое в данном случае равно «PRESENT» или равно null, если Entry отсутствует.
  4. Метод add Hashset затем возвращает true, если возвращаемое значение из Hashmap равно нулю, в противном случае false, что означает, что запись уже существует ...
Шив
источник
0

Чтобы сказать это по-другому: Когда вы вставляете пару ключ-значение в HashMap, где ключ уже существует (в некотором смысле hashvalue () дает одно и то же значение, а true () имеет значение true, но эти два объекта по-прежнему могут отличаться несколькими способами). ), ключ не заменяется, но значение перезаписывается. Ключ просто используется, чтобы получить hashvalue () и найти значение в таблице вместе с ним. Поскольку 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 ключ никогда не заменяется. Надеюсь, я смогу убрать путаницу.

Кунал Кумар
источник