将重复键放入HashMap时会发生什么?

时间:2009-11-03 20:18:00

标签: java hashmap hashtable

如果我多次将相同的密钥传递给HashMap的{​​{1}}方法,那么原始值会发生什么变化?如果价值重复怎么办?我没有找到任何关于此的文件。

案例1:键的覆盖值

put

我们得到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"));

案例2:重复值

surely not one

我们得到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是否像引用最后一个值的桶(但在内存中)?

12 个答案:

答案 0 :(得分:287)

根据定义,put命令替换了与映射中给定键关联的先前值(概念上类似于基本类型的数组索引操作)。

地图只是删除了对该值的引用。如果没有其他内容包含对该对象的引用,则该对象将有资格进行垃圾回收。此外,Java返回与给定键关联的任何先前值(如果不存在,则返回null),因此您可以确定存在的值并在必要时维护引用。

此处提供更多信息:HashMap Doc

答案 1 :(得分:70)

您可以在Map#put(K, V)的javadoc中找到答案(实际上会返回一些内容):

public V put(K key,
             V value)
     

将指定的值与此映射中的指定键相关联   (可选操作)。如果是地图   以前包含映射   这个键,旧值被替换为   指定的值。 (说地图m   包含键k if的映射   并且只有m.containsKey(k)会   返回true。)

     

<强>参数:
          key - 与指定值关联的键           value - 与指定键关联的值。

     

<强>返回:
          与指定密钥关联的先前值,如果没有,则为null   映射key。 (如果实施支持null值,则null返回还可以表明地图之前已将key与指定的null相关联。)

因此,如果在调用mymap.put("1", "a string")时没有分配返回的值,它就会被取消引用,因此有资格进行垃圾回收。

答案 2 :(得分:18)

键的先前值被删除并替换为新值。

如果您希望保留所有值,则可以考虑实施以下内容:

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));
         }
      }
   }
}

答案 3 :(得分:17)

它的键/值功能,您不能为多个值设置重复键,因为当您想要获取实际值时,其中一个值属于输入键,在您的示例中,当您想要获取值时“1”是哪一个?!这是为每个值都有唯一键的原因但你可以通过java标准库得到一个技巧:

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

答案 4 :(得分:12)

将指定的值与此映射中的指定键相关联。如果地图以前包含该键的映射,则将替换旧值。

答案 5 :(得分:4)

您的问题是否地图就像一个桶:没有。

它就像一个name=value对的列表,而name不需要是一个字符串(尽管如此)。

要获取元素,可以将密钥传递给get() - 方法,该方法为您提供返回的已分配对象。

哈希地图意味着如果您尝试使用get方法检索对象,则不会将真实对象与您提供的对象进行比较,因为它需要遍历其列表并比较()您使用当前元素提供的密钥。

这样效率低下。相反,无论您的对象包含什么,它都会从两个对象计算所谓的哈希码并对其进行比较。比较两个int而不是两个完整(可能非常复杂)的对象更容易。您可以将哈希码想象为具有预定义长度(int)的摘要,因此它不是唯一的并且具有冲突。您在我插入链接的文档中找到了哈希码的规则。

如果您想了解更多相关信息,可能需要查看有关javapractices.comtechnofundo.com

的文章

问候

答案 6 :(得分:3)

我一直用:

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");
}

答案 7 :(得分:3)

替换相应键中的现有值 。如果不存在具有相同名称的键,则它将使用提供的值创建一个键。 例如:

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

输出 键=“ 1”,值=“两个”

因此,先前的值将被覆盖。

答案 8 :(得分:1)

顺便说一下,如果你想要一些语义,比如只有当这个键不存在时才放。您可以concurrentHashMap使用putIfAbsent()功能。 看看这个:

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

concurrentHashMap具有高性能的线程安全性,因为它使用“ lock striping ”机制来提高吞吐量。

答案 9 :(得分:1)

是的,这意味着所有带有值的1个键都会被最后添加的值覆盖,在这里你添加“肯定不是一个”,所以它只显示“肯定不是一个”。

即使您尝试使用循环显示,它也只会显示一个具有相同键的键和值。

答案 10 :(得分:1)

JDK的地图不用于在重复的键下存储数据。

  • 充其量新值将覆盖之前的值。

  • 最糟糕的情况是个例外(例如,当您尝试将其作为流收集时):

无重复:

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

  

好的。您将获得:$ 2 ==> {one = one}

重复的流:

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

  

Exception java.lang.IllegalStateException:重复键1(尝试合并值1而不是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)   |在AbstractPipeline.copyInto(AbstractPipeline.java:484)   |在AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)   |在ReduceOps $ ReduceOp.evaluateSequential(ReduceOps.java:913)   |在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标头可以具有相同的字段...)

祝你好运! :)

答案 11 :(得分:-1)

         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<>();
    }
}