Что происходит, когда дублирующий ключ помещается в HashMap?

Если я передаю один и тот же ключ несколько раз методу HashMap s put, что произойдет с исходным значением? А что, если даже значение повторяется? Я не нашел никакой документации по этому вопросу.

Случай 1: Перезаписанные значения для ключа

Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","not one");
mymap.put("1","surely not one");
System.out.println(mymap.get("1"));

Получаем surely not one.

Случай 2: Дублирующее значение

Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","not one");
mymap.put("1","surely not one");
// The following line was added:
mymap.put("1","one");
System.out.println(mymap.get("1"));

Получаем one.

Но что происходит с другими значениями? Я преподавал основы студенту, и меня спросили об этом. Является ли Map как ведро, на которое ссылается последнее значение (но в памяти)?

+242
03 нояб. '09 в 20:17
источник поделиться
12 ответов

По определению команда put заменяет предыдущее значение, связанное с данным ключом на карте (концептуально, как операция индексирования массива для примитивных типов).

Карта просто отбрасывает ссылку на значение. Если ничто иное не содержит ссылку на объект, этот объект становится пригодным для сбора мусора. Кроме того, Java возвращает любое предыдущее значение, связанное с данным ключом (или null, если оно отсутствует), поэтому вы можете определить, что там было, и при необходимости поддерживать ссылку.

Дополнительная информация здесь: HashMap Doc

+278
03 нояб. '09 в 20:21
источник

Связанные вопросы


Похожие вопросы

Вы можете найти свой ответ в javadoc Map # put (K, V) (который фактически что-то возвращает):

public V put(K key,
             V value)

Связывает указанное значение с указанным ключом на этой карте (дополнительная операция). Если карта ранее содержало отображение для этот ключ, старое значение заменяется на указанное значение. (Отображается карта mсодержать отображение для ключа k, если и только если m.containsKey(k) будет return true.)

Параметры:
        key - ключ, с которым должно быть связано указанное значение.
        value - значение, связанное с указанным ключом.

Возврат:
        предыдущее значение, связанное с указанным ключом, или null, если не было отображение для key. (Возврат A null также может указывать, что ранее связанная карта null с указанным key, если реализация поддерживает значения null.)

Поэтому, если вы не назначаете возвращаемое значение при вызове mymap.put("1", "a string"), оно просто перестает ссылаться и, следовательно, имеет право на сбор мусора.

+70
03 нояб. '09 в 20:22
источник

Предыдущее значение для ключа отбрасывается и заменяется новым.

Если вы хотите сохранить все значения, предоставленные ключом, вы можете подумать о том, чтобы реализовать что-то вроде этого:

import org.apache.commons.collections.MultiHashMap;
import java.util.Set;
import java.util.Map;
import java.util.Iterator;
import java.util.List;
public class MultiMapExample {

   public static void main(String[] args) {
      MultiHashMap mp=new MultiHashMap();
      mp.put("a", 10);
      mp.put("a", 11);
      mp.put("a", 12);
      mp.put("b", 13);
      mp.put("c", 14);
      mp.put("e", 15);
      List list = null;

      Set set = mp.entrySet();
      Iterator i = set.iterator();
      while(i.hasNext()) {
         Map.Entry me = (Map.Entry)i.next();
         list=(List)mp.get(me.getKey());

         for(int j=0;j<list.size();j++)
         {
          System.out.println(me.getKey()+": value :"+list.get(j));
         }
      }
   }
}
+18
22 мар. '12 в 12:45
источник

это функция Key/Value, и вы не можете иметь дублирующий ключ для нескольких значений, потому что, когда вы хотите получить фактическое значение, которое одно из значений принадлежит введенному ключу в вашем примере, когда вы хотите получить значение "1", какой из них?!
что причины имеют уникальный ключ для каждого значения, но вы могли бы получить трюк от java standard lib:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class DuplicateMap<K, V> {

    private Map<K, ArrayList<V>> m = new HashMap<>();

    public void put(K k, V v) {
        if (m.containsKey(k)) {
            m.get(k).add(v);
        } else {
            ArrayList<V> arr = new ArrayList<>();
            arr.add(v);
            m.put(k, arr);
        }
    }

     public ArrayList<V> get(K k) {
        return m.get(k);
    }

    public V get(K k, int index) {
        return m.get(k).size()-1 < index ? null : m.get(k).get(index);
    }
}

и вы можете использовать его таким образом:

    public static void main(String[] args) {
    DuplicateMap<String,String> dm=new DuplicateMap<>();
    dm.put("1", "one");
    dm.put("1", "not one");
    dm.put("1", "surely not one");
    System.out.println(dm.get("1"));
    System.out.println(dm.get("1",1));
    System.out.println(dm.get("1", 5));
}

и результат печати:

[one, not one, surely not one]
not one
null
+17
09 февр. '16 в 21:03
источник

Связывает указанное значение с указанным ключом на этой карте. Если ранее карта содержала отображение для ключа, заменили старое значение.

+11
12 июл. '17 в 16:18
источник

На ваш вопрос, была ли карта похожей на ведро: no.

Он похож на список с парами name=value, тогда как name не обязательно должен быть String (может быть, хотя).

Чтобы получить элемент, вы передаете свой ключ методу get(), который возвращает вам назначенный объект.

И карта Хеш означает, что если вы пытаетесь восстановить свой объект с помощью метода get, он не будет сравнивать реальный объект с тем, который вы предоставили, потому что ему нужно будет итерации по его списку и сравнения() ключа, который вы предоставили с текущим элементом.

Это было бы неэффективно. Вместо этого, независимо от того, из чего состоит ваш объект, он вычисляет так называемый хэш-код из обоих объектов и сравнивает их. Легче сравнить два int вместо двух целых (возможно, глубоко сложных) объектов. Вы можете представить хэш-код как сводку с предопределенной длиной (int), поэтому она не уникальна и имеет коллизии. Вы найдете правила для хэш-кода в документации, к которой я вставлял ссылку.

Если вы хотите узнать больше об этом, вы можете взглянуть на статьи на javapractices.com и technofundo.com

рассматривает

+4
03 нояб. '09 в 20:44
источник

Я всегда использовал:

HashMap<String, ArrayList<String>> hashy = new HashMap<String, ArrayList<String>>();

если я хотел применить несколько вещей к одному идентифицирующему ключу.

public void MultiHash(){
    HashMap<String, ArrayList<String>> hashy = new HashMap<String, ArrayList<String>>();
    String key = "Your key";

    ArrayList<String> yourarraylist = hashy.get(key);

    for(String valuessaved2key : yourarraylist){
        System.out.println(valuessaved2key);
    }

}

вы всегда можете сделать что-то подобное и создать себе лабиринт!

public void LOOK_AT_ALL_THESE_HASHMAPS(){
    HashMap<String, HashMap<String, HashMap<String, HashMap<String, String>>>> theultimatehashmap = new HashMap <String, HashMap<String, HashMap<String, HashMap<String, String>>>>();
    String ballsdeep_into_the_hashmap = theultimatehashmap.get("firststring").get("secondstring").get("thirdstring").get("forthstring");
}
+3
03 февр. '15 в 2:41
источник

BTW, если вам нужна семантика, например, только если этот ключ не существует. вы можете использовать concurrentHashMap с функцией putIfAbsent(). Проверьте это:

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html#put(K,%20V)

concurrentHashMap является потокобезопасным с высокой производительностью, поскольку для улучшения пропускной способности используется механизм блокировки.

+1
17 июн. '15 в 18:19
источник

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

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

+1
24 авг. '16 в 10:52
источник

Он заменяет существующее значение на карте для соответствующего ключа. И если не существует ключа с таким именем, он создает ключ с указанным значением. например:

Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","two");

Ключ ВЫХОДА= "1", value = "два"

Итак, предыдущее значение перезаписывается.

0
01 февр. '19 в 6:51
источник

Карты из JDK не предназначены для хранения данных под дублированными ключами.

  • В лучшем случае новое значение переопределит предыдущие.

  • Хуже сценарий является исключением (например, когда вы пытаетесь собрать его в виде потока):

Нет дубликатов:

Stream.of("one").collect(Collectors.toMap(x → x, x → x))

Хорошо. Вы получите: $ 2 ==> {один = один}

Дублированный поток:

Stream.of("one", "not one", "surely not one").collect(Collectors.toMap(x → 1, x → x))

Исключение java.lang.IllegalStateException: дубликат ключа 1 (попытка объединения значений один, а не один) | в Collectors.duplicateKeyException(Collectors.java:133) | в Collectors.lambda $ uniqKeysMapAccumulator $ 1 (Collectors.java:180) | в ReduceOps $ 3ReducingSink.accept(ReduceOps.java:169) | в Spliterators $ ArraySpliterator.forEachRemaining(Spliterators.java:948) | at AbstractPipeline.copyInto(AbstractPipeline.java:484) | at AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) | at ReduceOps $ ReduceOp.evaluateSequential(ReduceOps.java:913) | at AbstractPipeline.evaluate(AbstractPipeline.java:234) | в ReferencePipeline.collect(ReferencePipeline.java:578) | в (# 4: 1)

Для работы с дублированными ключами - используйте другой пакет, например: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html.

Существует много других реализаций, имеющих дело с дублированными ключами. Они необходимы для Интернета (например, дублированные ключи cookie, заголовки Http могут иметь одинаковые поля,...)

Удачи! :)

0
01 февр. '19 в 6:38
источник
         HashMap<Emp, Emp> empHashMap = new HashMap<Emp, Emp>();

         empHashMap.put(new Emp(1), new Emp(1));
         empHashMap.put(new Emp(1), new Emp(1));
         empHashMap.put(new Emp(1), new Emp());
         empHashMap.put(new Emp(1), new Emp());
         System.out.println(empHashMap.size());
    }
}

class Emp{
    public Emp(){   
    }
    public Emp(int id){
        this.id = id;
    }
    public int id;
    @Override
    public boolean equals(Object obj) {
        return this.id == ((Emp)obj).id;
    }

    @Override
    public int hashCode() {
        return id;
    }
}


OUTPUT : is 1

Значит хэш-карта не позволяет дублировать, если вы правильно переопределили equals и hashCode().

HashSet также использует HashMap внутренне, см. исходный документ

public class HashSet{
public HashSet() {
        map = new HashMap<>();
    }
}
-1
03 мар. '15 в 0:39
источник

Посмотрите другие вопросы по меткам или Задайте вопрос