当一个重复的键被放入HashMap时会发生什么?

如果我将相同的键多次传递给HashMapput方法,原始值会发生什么变化?如果值重复呢?我没找到任何关于这个的文件。

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

557356 次浏览

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

映射只是删除了对该值的引用。如果没有其他对象保存对该对象的引用,则该对象符合垃圾收集的条件。此外,Java返回与给定键相关的任何先前值(如果不存在则返回null),因此您可以确定那里有什么并在必要时维护引用。

更多信息:HashMap医生

你可以在#把地图(K、V)的javadoc中找到答案(它实际返回一些东西):

public V put(K key,
V value)

将指定的值与此映射中的指定键关联 (可选操作)。如果地图 以前包含的映射 此键的旧值被替换为 指定的值。(表示映射m 包含键k的映射if 并且只有当m.containsKey(k)会 返回true。)< / p > < p > 参数: < br > key -要与指定值相关联的key value -与指定键相关联的值。< / p > < p > 返回: < br > 与指定key相关联的前一个值,或null(如果没有) key的映射。(如果实现支持null值,null返回值也可以指示先前将null与指定的key关联的映射。

因此,如果在调用mymap.put("1", "a string")时不分配返回值,它就会变成未引用的,从而符合垃圾收集的条件。

对于你的问题,地图是否像一个桶:不是。

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

要获取一个元素,您将键传递给get()方法,该方法返回给您赋值的对象。

哈希map意味着如果你试图使用get-method检索你的对象,它不会将实际对象与你提供的对象进行比较,因为它需要遍历它的列表并compare()你提供的键与当前元素。

这将是低效的。相反,不管你的对象由什么组成,它都会从两个对象中计算一个所谓的hashcode并进行比较。比较两个__abc0而不是两个完整的(可能非常复杂)对象更容易。您可以将hashcode想象成具有预定义长度(int)的摘要,因此它不是唯一的,并且具有冲突。您可以在我插入链接的文档中找到hashcode的规则。

如果你想了解更多,你可能想看看关于javapractices.comtechnofundo.com的文章

问候

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

如果你想保留一个键给定的所有值,你可以考虑实现这样的东西:

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

我总是用:

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

BTW,如果你想要一些语义,比如只有当这个键不存在时才放。你可以在putIfAbsent()函数中使用concurrentHashMap

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

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

它是键/值特性,你不能有多个值的重复键,因为当你想要获得实际值时,哪个值属于输入的键
,在你的例子中,当你想要获得“1”的值时,哪个是它?!
这是每个值都有唯一键的原因,但你可以通过Java标准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

是的,这意味着所有有值的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))

java.lang.IllegalStateException:重复键1(尝试合并值为1而不是1) |在收藏家。duplicateKeyException (Collectors.java: 133) |在收藏家。λuniqKeysMapAccumulator 1美元(Collectors.java: 180) |在ReduceOps$3ReducingSink。接受(ReduceOps.java: 169) | at Spliterators$ArraySpliterator。forEachRemaining (Spliterators.java: 948) |在AbstractPipeline。copyInto (AbstractPipeline.java: 484) |在AbstractPipeline。wrapAndCopyInto (AbstractPipeline.java: 474) 在$ReduceOp的|。evaluateSequential (ReduceOps.java: 913) |在AbstractPipeline。评估(AbstractPipeline.java: 234) |在ReferencePipeline。收集(ReferencePipeline.java: 578) | at (#4:1)

处理重复键-使用其他包,例如: https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html < / p > 有很多其他的实现处理重复的键。 这些是web所需要的(例如,重复的cookie密钥,Http报头可以有相同的字段,…

好运!:)

它在对应键的映射中替换现有值。如果不存在同名的键,则使用所提供的值创建一个键。 如:< / p >
Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","two");

< >强输出 Key = "1", value = "two"

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