Java HashMap get 有效但 containsKey 无效
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1104030/
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
Java HashMap get works but containsKey does not
提问by burntsugar
I am trying to locate a key in a HashMap. I can print the selected key by using 'get' but when I use 'containsKey' in an if statement, it is not found.
我正在尝试在 HashMap 中找到一个键。我可以使用“get”打印选定的键,但是当我在 if 语句中使用“containsKey”时,找不到它。
I KNOW the key is present in the Map but it keeps returning false. Any ideas people?
我知道密钥存在于地图中,但它一直返回 false。有什么想法吗?
My code:
我的代码:
public static boolean checkLowerStructuralSupport(Location location) {
boolean hasSupport = false;
Location supportingLocation = new Location(location.getX(), location.getY(), location.getZ() - 1);
System.out.println(_levels.get(supportingLocation.getZ()).getLevelSites2().get(supportingLocation)); //works
if (_levels.get(supportingLocation.getZ()).getLevelSites2().containsKey(supportingLocation)) {
hasSupport = true;
} else {
hasSupport = false;
}
return hasSupport;
}
Here is the code for the Location class:
下面是 Location 类的代码:
public class Location {
protected int _x;
protected int _y;
protected int _z;
public Location(int xAxis, int yAxis, int zAxis) {
this._x = xAxis;
this._y = yAxis;
this._z = zAxis;
}
public void equals() {
//not implemented yet
}
public void HashCode() {
//not implemented yet
}
public String toString() {
String locationString = Integer.toString(_x) + Integer.toString(_y) + Integer.toString(_z);
return locationString;
}
public void setX(int XAxis) {
this._x = XAxis;
}
public int getX() {
return this._x;
}
public void setY(int YAxis) {
this._y = YAxis;
}
public int getY() {
return this._y;
}
public void setZ(int ZAxis) {
this._z = ZAxis;
}
public int getZ() {
return this._z;
}
}
采纳答案by Adam Paynter
You must ensure that the Location
class has properly implemented its hashCode()
and equals(Object)
methods (documentation). That is, if two Location
objects are effectively equal, they should share a common hash code and their equals
method should return true
.
您必须确保Location
该类已正确实现其hashCode()
和equals(Object)
方法(文档)。也就是说,如果两个Location
对象实际上相等,它们应该共享一个公共哈希码并且它们的equals
方法应该返回true
。
回答by Pablo Santa Cruz
In Locationclass, make sure you are overriding hashCodeand equalsmethods.
在Location类中,确保您覆盖了hashCode和equals方法。
If you are, can you post them?
如果是的话,可以发一下吗?
回答by dustmachine
Both get()
and containsKey()
are using the Location
class's hashCode()
method. The equals()
method isn't called unless there is a hash collision. (thus, HashMap's get() won't use equals()
in every situation.)
双方get()
并containsKey()
使用Location
类的hashCode()
方法。equals()
除非发生哈希冲突,否则不会调用该方法。(因此,HashMap 的 get() 不会equals()
在所有情况下使用。)
For your Location
class, did you by chance happen to implement your own version of hashCode()
? The hashCode()
method should be implemented carefully. Joshua Bloch described all the details in the book Effective Java, portions of which are online... I'll go find the link to those sample chapters: Effective Java Sample Chapters. You want chapter 3.
对于您的Location
班级,您是否碰巧实现了自己的hashCode()
? 该hashCode()
方法应谨慎实施。Joshua Bloch 在Effective Java一书中描述了所有细节,其中部分内容在线......我将找到这些示例章节的链接: Effective Java Sample Chapters。你要第三章。
As I asked in the comment to the question, Where does your _levels
variable come from? I don't see it declared inside that method and your naming (underscore prefix, are you importing that convention from some other language?) suggests that it "lives" outside this method. Perhaps other code is changing it during execution? Please let us know when you solve it; the suspense is killing me.
正如我在对问题的评论中所问的那样,您的_levels
变量来自哪里?我没有看到它在该方法中声明,并且您的命名(下划线前缀,您是否从其他语言导入该约定?)表明它“存在于”该方法之外。也许其他代码在执行过程中正在改变它?解决后请告诉我们;悬念正在杀死我。
回答by froderik
containsKey uses the method equals to compare the param with the entries in the key set. So the Location class needs to have a equals method that is good. The default equals method in java.lang.Object only returns true when both objects are the same object. In this case you probably have 2 different instances that needs to be compared and need a custom equals method.
containsKey 使用方法 equals 将参数与键集中的条目进行比较。所以Location类需要有一个好的equals方法。java.lang.Object 中的默认 equals 方法仅在两个对象是同一对象时才返回 true。在这种情况下,您可能有 2 个不同的实例需要进行比较,并且需要一个自定义的 equals 方法。
回答by Brian Agnew
To avoid problems, your equals()
and hashCode()
methods should be consistent and conform to the requirements (as noted elsewhere).
为避免出现问题,您的方法equals()
和hashCode()
方法应保持一致并符合要求(如别处所述)。
Additionally, hashCode() should notrely on mutable members, otherwise your calculated hash code can change, and this affects the internal workings of the HashMap
. That will reveal itself in an inability to retrieve stuff from Hash*
collections.
此外,hashCode()方法应该不依靠可变成员,否则你的计算哈希码可以改变,而这种影响的内部工作HashMap
。这将表明无法从Hash*
集合中检索内容。
回答by Markus Lausberg
As descibed here, you have to override the equals(Object)method.
如此处所述,您必须覆盖equals(Object)方法。
The reason why get(Object) is working is, that HashMap will calculate the Hash for your Location class and returns the Object the hascode points to.
get(Object) 工作的原因是,HashMap 将为您的 Location 类计算哈希并返回 hascode 指向的对象。
containsKey(Object) calculates the hash key and gets the object the hash is pointed to. The object from the HashMap will compare to the Object you put in. For these comparison the equals method is used. When you do not override he equals method, true is returned, when the object reference to the same instance.
containsKey(Object) 计算散列键并获取散列指向的对象。来自 HashMap 的对象将与您放入的对象进行比较。对于这些比较,使用了 equals 方法。当你不重写他的equals方法时,返回true,当对象引用同一个实例时。
From HashMap
来自 HashMap
/**
* Check for equality of non-null reference x and possibly-null y.
*/
static boolean eq(Object x, Object y) {
return x == y || x.equals(y);
}
From Object
从对象
public boolean equals(Object obj) {
return (this == obj);
}
From the javadoc of equals
来自 equals 的 javadoc
The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
Object 类的 equals 方法实现了对象上最有区别的可能等价关系;也就是说,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象(x == y 的值为 true)时,此方法才返回 true。
请注意,每当重写此方法时,通常都需要重写 hashCode 方法,以维护 hashCode 方法的一般约定,即相等的对象必须具有相等的哈希码。
回答by Hyman Leow
The only thing I can think of that will cause this is if the state of supportingLocation
is somehow being mutated between the get(...)
call and the containsKey(...)
.
我唯一能想到的会导致这种情况的是,如果 的状态supportingLocation
在get(...)
调用和containsKey(...)
.
Assuming the code snippet you posted is the exact code that's causing problems, the only place this could occur is if one of Location#getZ(...)
, Location#hashCode()
or Location#equals(Object)
mutates the state of Location (or the Location constructor, or one of these methods starts a thread that randomly changes the state of the Location instance, but I think we can rule that out).
假设代码片段您发布的确切的代码是造成问题,唯一的地方可能发生这种情况是如果一个Location#getZ(...)
,Location#hashCode()
或Location#equals(Object)
变异位置的状态(或位置构造,或者这些方法之一启动一个线程随机变化的状态Location 实例,但我认为我们可以排除这一点)。
Could you verify that none of the methods above are changing the state of the supportingLocation
instance? While I am not familiar with the Location
class itself, I'd venture to guess that a class like that would ideally be immutable.
您能否验证上述方法均未更改supportingLocation
实例的状态?虽然我对Location
类本身并不熟悉,但我敢于猜测这样的类在理想情况下是不可变的。
Edit:
To clarify, when I say that Location#getZ()
etc aren't mutating the Location, what I mean is:
编辑:澄清一下,当我说Location#getZ()
等不会改变位置时,我的意思是:
Location x = new Location(1,2,3);
Location y = new Location(1,2,3);
boolean eq1 = x.equals(y);
int hash1 = x.hashCode();
x.getZ(); // this should *not* mutate the state of x
boolean eq2 = x.equals(y);
int hash2 = x.hashCode();
In the end, eq1 should be equal to eq1, and hash1 should be equal to hash2. If this is not the case, getZ() is mutating the state of x (or equals, or hashCode, or worse, those methods are completely off), and will result in the behavior you observed.
最后,eq1 应该等于 eq1,hash1 应该等于 hash2。如果不是这种情况, getZ() 正在改变 x 的状态(或等于,或 hashCode,或更糟的是,这些方法完全关闭),并将导致您观察到的行为。
回答by Aaron K
Take a peak at the source code for the HashMap implementation. Both get and containsKey use the hasCode() and equals() methods of your key object.
重点看一下 HashMap 实现的源代码。get 和 containsKey 都使用密钥对象的 hasCode() 和 equals() 方法。
The only real difference, and as was pointed out, it is a trivial null check, is in the comparisons:
唯一真正的区别,正如所指出的,它是一个微不足道的空检查,是在比较中:
get:
得到:
((k = e.key) == key || key.equals(k))
containsKey:
包含密钥:
((k = e.key) == key || (key != null && key.equals(k)))
where e is of type Entry for a HashMap.
其中 e 是 HashMap 的 Entry 类型。
So, if you do not have a strong implementations of hashCode() and/or equals() you will have a problem. Additionally, if your keys were mutated (I see that you did not declare the class fields final) you could have an issue.
因此,如果您没有 hashCode() 和/或 equals() 的强大实现,您将遇到问题。此外,如果您的密钥发生了变异(我看到您没有将类字段声明为 final),您可能会遇到问题。
Take the following example:
以下面的例子为例:
public class HashMapTest {
static class KeyCheck {
int value;
public KeyCheck(int value) { this.value = value; }
public void setValue(int value) { this.value = value; }
@Override public int hashCode() { return value; }
@Override public boolean equals(Object o) {
return ((KeyCheck)o).value == this.value;
}
}
public static void main(String args[]) {
HashMap<KeyCheck, String> map = new HashMap<KeyCheck, String>();
KeyCheck k1 = new KeyCheck(5);
KeyCheck k2 = new KeyCheck(5);
map.put(k1, "Success");
System.out.println("Key: " + k1 + " Get: " + map.get(k1) +
" Contains: " + map.containsKey(k1));
System.out.println("Key: " + k2 + " Get: " + map.get(k2) +
" Contains: " + map.containsKey(k2));
k1.setValue(10);
System.out.println("Key: " + k1 + " Get: " + map.get(k1) +
" Contains: " + map.containsKey(k1));
System.out.println("Key: " + k2 + " Get: " + map.get(k2) +
" Contains: " + map.containsKey(k2));
}
}
This will print out:
这将打印出:
Key: HashMapTest$KeyCheck@5 Get: Success Contains: true
Key: HashMapTest$KeyCheck@5 Get: Success Contains: true
Key: HashMapTest$KeyCheck@a Get: null Contains: false
Key: HashMapTest$KeyCheck@5 Get: null Contains: false
键:HashMapTest$KeyCheck@5 获取:成功包含:true
键:HashMapTest$KeyCheck@5 获取:成功包含:true
键:HashMapTest$KeyCheck@a 获取:null 包含:false
键:HashMapTest$KeyCheck@5 获取:null 包含: 错误的
As you can see, in this case the mutability caused the hashCode() to change, which ruined everything.
正如你所看到的,在这种情况下,可变性导致 hashCode() 改变,这破坏了一切。
回答by Fareed Alnamrouti
i think sometime you need the hash code and sometimes not so i think in this way you can turn of the hash code checking when you want buy changing the hash code for all objects you want to 0
我认为有时您需要哈希码,有时则不需要,所以我认为通过这种方式,您可以在购买时关闭哈希码检查,将所有想要的对象的哈希码更改为 0
public class sample(){
@JsonIgnore
private int hashCode = super.hashCode();
public void setHashCode(int hashCode){
this.hashCode = hashCode;
}
@Override
public int hashCode(){
return this.hashCode;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ReflectObject other = (ReflectObject) obj;
if (this.hashCode != other.hashCode) {
return false;
}
return true;
}
}