如果我多次将相同的密钥传递给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
是否像引用最后一个值的桶(但在内存中)?
答案 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.com和technofundo.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<>();
}
}