如果我将相同的键多次传递给HashMap的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"));

我们得到的肯定不是1。

案例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"));

我们得到一个。

但是其他的值会怎样呢?我在给一个学生教授基础知识,有人问我这个问题。Map是否像一个引用最后一个值的桶(但在内存中)?


当前回答

JDK中的映射并不用于在重复的键下存储数据。

在最好的情况下,新值将覆盖之前的值。 更糟糕的情况是异常(例如,当你试图收集它作为一个流):

没有重复:

Stream.of(“一”).collect(收藏者。toMap(x -> x, x -> x))

好的。你将得到:$2 ==> {one=one}

复制流:

流。“一个”,“不是一个”,“肯定不是一个”。toMap(x -> 1, x -> x))

Exception java.lang.IllegalStateException: Duplicate key 1 (attempted merging values one and not one) | at Collectors.duplicateKeyException (Collectors.java:133) | at Collectors.lambda$uniqKeysMapAccumulator$1 (Collectors.java:180) | at ReduceOps$3ReducingSink.accept (ReduceOps.java:169) | at 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) | at ReferencePipeline.collect (ReferencePipeline.java:578) | at (#4:1)

要处理重复的密钥-使用其他包,例如: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html

有很多其他的实现处理重复的键。 这些是web所需要的(例如,重复的cookie密钥,Http报头可以有相同的字段,…)

好运!:)

其他回答

它是键/值特性,你不能有多个值的重复键,因为当你想获得实际值时,哪个值属于输入的键在你的例子中,当你想获得值“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

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

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

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

concurrentHashMap是线程安全的高性能,因为它使用“锁条带”机制来提高吞吐量。

它替换对应键的映射中现有的值。如果不存在同名的键,则使用所提供的值创建一个键。 例如:

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

输出 Key = "1", value = " 2 "

所以,之前的值会被覆盖。

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