Вставка в HashMap против Hashset - PullRequest
0 голосов
/ 05 мая 2018

В случае HashMap оно заменяет старое значение новым в случае дублирования ключа. В случае HashSet элемент вообще не вставляется. Поскольку HashSet реализует HashMap внутренне. Почему эти две вставки обрабатываются по-разному?

1 Ответ

0 голосов
/ 05 мая 2018

HashMap заменяет старое значение новым, когда вы вставляете его с тем же ключом. Пример:

Map<Integer, String> map = new HashMap<>();
map.put(1, "first put");
System.out.println(map.get(1)); // <-- prints `first put`
map.put(1, "second put");
System.out.println(map.get(1)); // <-- prints `second put`

Таким образом, в основном, когда новое значение прибывает с ключом, уже присутствующим на карте, оно просто заменяет значение для этого ключа, потому что даже если ключ тот же, новое значение может отличаться от значения, связанного с этим ключом в карта.

В случае HashSet есть только ключ , значение отсутствует. Поэтому, когда прибывает уже существующий key, делать это не нужно, он уже есть.

Что касается внутренней реализации HashSet, на самом деле он использует HashMap внутри, но для этого он просто создает один object:

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

и когда вам нужно add некоторые key для установки, он просто вызывает put(key, present) на этой карте, используя один и тот же объект для всех записей (чтобы не выделять много бесполезных объектов:

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

Таким образом, в целом HashSet использует внутренне HashMap, и когда вы помещаете что-то в хэш-карту, всегда присваивается новое значение вместо старого, однако key нет, и как HashSet использует свои ключи в качестве ключей в HashMap, тогда, если вы вставите дублирующий ключ в HashSet, он не удалит старый. Пример: * +1032 *

Предположим, у нас есть некоторый класс сущностей, который имеет 2 поля: int id и строку name, но только id участвует в реализации equals метода.

    Entity entity1 = new Entity(1, "some name");
    Entity entity2 = new Entity(1, "some other name");
    System.out.println(entity1.equals(entity2)); // returns true

    Map<Integer, Entity> map = new HashMap<>();
    map.put(entity1.id, entity1);
    map.put(entity2.id, entity2);
    System.out.println(map.get(entity1.id).name); // returns "some other name"

    Map<Entity, String> keyMap = new HashMap<>();
    keyMap.put(entity1, entity1.name);
    keyMap.put(entity2, entity2.name);
    System.out.println(keyMap.keySet()); // returns [Entity{id=1, name='some name'}]
    System.out.println(keyMap.values()); // returns [some other name]

    Set<Entity> set = new HashSet<>();
    set.add(entity1);
    set.add(entity2);
    System.out.println(new ArrayList<>(set)); // returns [Entity{id=1, name='some name'}]

Также на это также не следует полагаться, поскольку его внутренние детали реализации, которые могут быть изменены в будущих выпусках, HashMap и HashSet используют equals, проверяют, является ли объект тем же. Если у вас есть два объекта, которые equals возвращают true, но вы все равно хотите относиться к ним по-разному, скорее всего, в вашем дизайне сущности есть какая-то проблема, однако бывают редкие случаи, когда inded дает желаемый эффект, в таких случаях вы можно взглянуть на IdentityHashMap.

...