Заменяет ли добавление повторяющегося значения в 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. Трудно знать, хотя, если вы не являетесь одним из разработчиков классов.
Кеппил

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

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


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 ключ никогда не заменяется. Надеюсь, я смогу убрать путаницу.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.