Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/343.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java HashMap包含几个具有相同值的不同键?_Java_Arraylist_Hashmap_Immutability_Mutable - Fatal编程技术网

Java HashMap包含几个具有相同值的不同键?

Java HashMap包含几个具有相同值的不同键?,java,arraylist,hashmap,immutability,mutable,Java,Arraylist,Hashmap,Immutability,Mutable,我所做的很简单:我想创建一个HashMap,其中Pair作为键,ArrayList作为值。对是自定义类,包含元素l(左)和r(右) 起初,我是这样做的: Map<Pair, ArrayList<Integer>> hashmap = new HashMap<>(); ArrayList<String> stringList = new ArrayList<>(); stringList.add("a"); stringList.add(

我所做的很简单:我想创建一个
HashMap
,其中
Pair
作为键,
ArrayList
作为值。
对是自定义类,包含元素
l
(左)和
r
(右)

起初,我是这样做的:

Map<Pair, ArrayList<Integer>> hashmap = new HashMap<>();
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
stringList.add("a");
Pair<String, Integer> aPair = new Pair<>(" ", 1); // HERE will be changed!

for (String aString: stringList) {
  aPair.setLeft(aString);
  if (!hashmap.containsKey(aPair)){
    hashmap.put(aPair, new ArrayList<Integer>());
  }
  hashmap.get(aPair).add(1);
}

for (Map.Entry<Pair, ArrayList<Integer>> entry: hashmap.entrySet()) {
  out.println(entry.getKey().getLeft() + " " + entry.getKey().getRight() + " " + entry.getValue());
}
Map<Pair, ArrayList<Integer>> hashmap = new HashMap<>();
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
stringList.add("a");

for (String aString: stringList) {
  Pair<String, Integer> aPair = new Pair<>(aString, 1); // HERE changed!
  if (!hashmap.containsKey(aPair)){
    hashmap.put(aPair, new ArrayList<Integer>());
  }
  hashmap.get(aPair).add(1);
}

for (Map.Entry<Pair, ArrayList<Integer>> entry: hashmap.entrySet()) {
  out.println(entry.getKey().getLeft() + " " + entry.getKey().getRight() + " " + entry.getValue());
}
c 1 [1]
b 1 [1]
a 1 [1, 1]
但是,如果我将上述代码更改为以下代码:

Map<Pair, ArrayList<Integer>> hashmap = new HashMap<>();
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
stringList.add("a");
Pair<String, Integer> aPair = new Pair<>(" ", 1); // HERE will be changed!

for (String aString: stringList) {
  aPair.setLeft(aString);
  if (!hashmap.containsKey(aPair)){
    hashmap.put(aPair, new ArrayList<Integer>());
  }
  hashmap.get(aPair).add(1);
}

for (Map.Entry<Pair, ArrayList<Integer>> entry: hashmap.entrySet()) {
  out.println(entry.getKey().getLeft() + " " + entry.getKey().getRight() + " " + entry.getValue());
}
Map<Pair, ArrayList<Integer>> hashmap = new HashMap<>();
ArrayList<String> stringList = new ArrayList<>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
stringList.add("a");

for (String aString: stringList) {
  Pair<String, Integer> aPair = new Pair<>(aString, 1); // HERE changed!
  if (!hashmap.containsKey(aPair)){
    hashmap.put(aPair, new ArrayList<Integer>());
  }
  hashmap.get(aPair).add(1);
}

for (Map.Entry<Pair, ArrayList<Integer>> entry: hashmap.entrySet()) {
  out.println(entry.getKey().getLeft() + " " + entry.getKey().getRight() + " " + entry.getValue());
}
c 1 [1]
b 1 [1]
a 1 [1, 1]
为什么会这样?这是一个类似的问题。但情况仍然不同

编辑:正如@Eran在下面的评论中提到的,自定义的
覆盖方法
hashCode()
equals()

@覆盖
public int hashCode(){返回left.hashCode()^right.hashCode();}
@凌驾
公共布尔等于(对象o){
如果(!(o instanceof Pair))返回false;
对pairo=(对)o;
返回this.left.equals(pairo.getLeft())&&
this.right.equals(pairo.getRight());
}

在第一个代码片段中,实际上您对map的每个条目都使用相同的key对象。您只需修改它的左值,但它仍然指向相同的内存地址。Map需要有唯一的密钥(每个密钥必须指向不同的内存地址),这就是为什么您需要为每个Map条目添加pair的新实例。

您正在危险的水域中行走,因为您的密钥是可变的,请阅读此文为什么这不是一个好主意-


好吧,仅你的例子就说明了为什么这不是一个好主意。您在映射中添加一个键实例,然后对其进行修改,从而有效地修改了hashmap中的所有键值对。

您的第一个代码片段不起作用,因为您正在对已在
hashmap
中用作键的相同
对实例进行变异。这允许相同的
Pair
实例作为键出现在
HashMap
的多个条目中(因为修改
Pair
实例后计算的新
hashCode
实例被映射到不包含任何条目的
HashMap
的新存储桶中),并有效地破坏
HashMap

您不应该对用作
HashMap
键的实例进行变异(除非您在更新它之前将其从
HashMap
中删除,并在以后将更新的版本放入
映射中)

如果对象的hashCode()值可以根据其状态进行更改,那么 在基于哈希的应用程序中使用此类对象作为键时必须小心 集合,以确保在 它们被用作散列键。所有基于哈希的集合都假定 对象的哈希值在用作 输入集合中的键。如果密钥的散列码在 在一个集合中,一些不可预测和混乱的结果 我可以跟着。在实践中,这通常不是问题——事实并非如此 使用列表之类的可变对象作为 哈希映射


从这个

是的。它们是超驰的@有没有一把
map
刀,它的
键可以更改?@ChangLiu钥匙可以更改,但您必须在更改前将其移除,更改后重新添加,以便地图将其存储在以后可以找到的位置。是的,我知道这一点。我想知道的是:你无法更新
。@ChangLiu我不知道。