更新 Java HashMap 键
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6767365/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Updating Java HashMap key
提问by Abidi
I was just wondering, what would happen if key of a HashMap
is mutable, test program below demonstrate that and I am unable to understand when both equals and hashCode
methods returns
true and same value, why does hashmap.containsKey
return false
.
我只是想知道,如果 a 的键HashMap
是可变的会发生什么,下面的测试程序证明了这一点,我无法理解当 equals 和hashCode
方法都返回 true 和相同的值时,为什么hashmap.containsKey
return false
。
public class MutableKeyHashMap {
public static void main(String []a){
HashMap<Mutable, String> map = new HashMap<Mutable, String>();
Mutable m1 = new Mutable(5);
map.put(m1, "m1");
Mutable m2 = new Mutable(5);
System.out.println(map.containsKey(m2));
m2.setA(6);
m1.setA(6);
Mutable m3 = map.keySet().iterator().next();
System.out.println(map.containsKey(m2)+" "+m3.hashCode()+" "+m2.hashCode()+" "+m3.equals(m2));
}
}
class Mutable {
int a;
public Mutable(int a) {
this.a = a;
}
@Override
public boolean equals(Object obj) {
Mutable m = (Mutable) obj;
return m.a == this.a ? true : false;
}
@Override
public int hashCode(){
return a;
}
public void setA(int a) {
this.a = a;
}
public int getA() {
return a;
}
}
This the output :
这是输出:
true false 6 6 true
真假 6 6 真
回答by ptomli
The javadocexplains it
该javadoc的解释它
Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.
注意:如果将可变对象用作映射键,则必须非常小心。如果对象的值以影响相等比较的方式更改,而对象是映射中的键,则不会指定映射的行为。
Basically, don't use mutable objects as keys in a Map, you're going to get burnt
基本上,不要使用可变对象作为 Map 中的键,你会被烧毁
To extrapolate, because the docs may not appear clear, I believe the pertinent point here is `changed in a manner that affects equals', and you seem to be assuming that equals(Object) is called each time contains is invoked. The docs don't say that, the wording implies they may be allowed to cache computations.
推断,因为文档可能看起来不清楚,我相信这里的相关点是“以影响等于的方式更改”,并且您似乎假设每次调用 contains 时都会调用 equals(Object)。文档没有这么说,措辞暗示他们可能被允许缓存计算。
Looking at the source, it seems that because your hashCode returns a different value (was 5, now 6), it's possible that it's being looked up in a different bucket based on implementation details.
查看源代码,似乎是因为您的 hashCode 返回了不同的值(以前是 5,现在是 6),因此可能会根据实现细节在不同的存储桶中查找它。
回答by Affe
You can think of if this way, the Map has 16 buckets. When you give it an object with A == 5, it tosses it into bucket 5. Now you can change A to 6, but it's still in bucket 5. The Map doesn't know you changed A, it doesn't rearrange things internally.
你可以这样想,如果这样,Map 有 16 个桶。当你给它一个 A == 5 的对象时,它把它扔到桶 5 中。现在你可以把 A 改成 6,但它仍然在桶 5 中。地图不知道你改变了 A,它不会重新排列东西内部。
Now you come over with another object with A == 6, and you ask the Map if it has one of those. It goes and looks in bucket 6 and says "Nope, nothing there." It's not going to go and check all the other buckets for you.
现在你带着另一个 A == 6 的对象过来,然后你问 Map 是否有其中一个。它在第 6 个桶中查看并说“不,那里什么都没有。” 它不会为您检查所有其他存储桶。
Obviously how things get put into buckets is more complicated than that, but that's how it works at the core.
显然,如何将事物放入桶中比这更复杂,但这就是它的核心工作方式。
回答by starblue
The HashMap
puts your object at the location for hash key 5
. Then you change the key to 6
and use containsKey
to ask the map whether it contains the object. The map looks at position 6
and finds nothing, so it answers false
.
将HashMap
在哈希键的位置让你的对象5
。然后您将键更改为6
并使用containsKey
来询问地图是否包含该对象。地图查看位置6
并没有发现任何内容,因此它回答false
。
So don't do that, then.
所以不要那样做。
回答by tskuzzy
When you put "m1" the first time around, hashCode()
was 5. Thus the HashMap
used 5 to place the value into the appropriate bucket. After changing m2
, the hashCode()
was 6 so when you tried looking for the value you put in, it the bucket it looked in was different.
当您第一次放置“m1”时,它hashCode()
是 5。因此HashMap
使用 5 将值放入适当的存储桶中。更改后m2
,hashCode()
值为 6,因此当您尝试查找放入的值时,它查找的存储桶是不同的。
回答by Jingguo Yao
A code example to accompany ptomli's answer.
伴随ptomli答案的代码示例。
import java.util.*;
class Elem {
private int n;
public Elem(int n) {
this.n = n;
}
public void setN(int n) {
this.n = n;
}
@Override
public int hashCode() {
return n;
}
@Override
public boolean equals(Object e) {
if (this == e)
return true;
if (!(e instanceof Elem))
return false;
Elem an = (Elem) e;
return n == an.n;
}
}
public class MapTest {
public static void main (String [] args) {
Elem e1 = new Elem(1);
Elem e2 = new Elem(2);
HashMap map = new HashMap();
map.put(e1, 100);
map.put(e2, 200);
System.out.println("before modification: " + map.get(e1));
e1.setN(9);
System.out.println("after modification using updated key: " + map.get(e1));
Elem e3 = new Elem(1);
System.out.println("after modification using key which equals to the original key: " + map.get(e3));
}
}
Compiles and runs it. The result is:
编译并运行它。结果是:
before modification: 100
after modification using updated key: null
after modification using key which equals to the original key: null
I am using Java 6 on Linux.
我在 Linux 上使用 Java 6。