我正在尝试在HashMap中找到一个键。我可以使用'get'打印所选键,但是当我在if语句中使用'containsKey'时,找不到它。
我知道密钥存在于Map中,但它一直返回false。人们有什么想法吗?
我的代码:
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;
}
以下是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;
}
}
答案 0 :(得分:23)
您必须确保Location
类已正确实施其hashCode()
和equals(Object)
方法(documentation)。也就是说,如果两个Location
个对象实际上相等,则它们应该共享一个公共哈希码,并且它们的equals
方法应该返回true
。
答案 1 :(得分:5)
如此处所述,您必须覆盖 equals(Object)方法。
get(Object)工作的原因是,HashMap将为您的Location类计算Hash并返回hascode指向的Object。
containsKey(Object)计算散列键并获取散列指向的对象。 HashMap中的对象将与您放入的Object进行比较。对于这些比较,使用equals方法。 当你不覆盖他的equals方法时,当对象引用同一个实例时返回true。
来自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);
}
来自对象
public boolean equals(Object obj) {
return (this == obj);
}
来自等于
的javadoc类Object的equals方法 实现最具辨别力的 可能的等价关系 对象;也就是说,对于任何非null 参考值x和y,这种方法 当且仅当x和y返回true 引用同一个对象(x == y有 值true)。
请注意,通常需要 每当覆盖hashCode方法 这个方法被覆盖,以便 保持一般合同 hashCode方法,表明了这一点 等于对象必须具有相等的哈希值 码。强>
答案 2 :(得分:2)
在位置课程中,请确保覆盖 hashCode 和等于方法。
如果你是,你可以张贴它们吗?
答案 3 :(得分:2)
containsKey使用方法equals将param与键集中的条目进行比较。所以Location类需要有一个好的equals方法。 java.lang.Object中的默认equals方法仅在两个对象都是同一个对象时才返回true。在这种情况下,您可能需要比较两个不同的实例,并且需要自定义的equals方法。
答案 4 :(得分:2)
我唯一能想到的就是supportingLocation
调用get(...)
和containsKey(...)
之间的Location#getZ(...)
状态变异。
假设您发布的代码段是引起问题的确切代码,唯一可能发生的情况是Location#hashCode()
,Location#equals(Object)
或supportingLocation
中的一个会改变位置状态(或者位置构造函数,或者这些方法之一启动一个随机更改Location实例状态的线程,但我认为我们可以将其排除在外。)
您能否验证上述方法都没有改变Location
实例的状态?虽然我不熟悉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();
等没有改变位置时,我的意思是:
{{1}}
最后,eq1应该等于eq1,而hash1应该等于hash2。如果不是这种情况,getZ()会改变x的状态(或等于或者hashCode,或者更糟糕的是,那些方法完全关闭),并且会导致你观察到的行为。
答案 5 :(得分:1)
get()
和containsKey()
都使用Location
类的hashCode()
方法。除非存在哈希冲突,否则不会调用equals()
方法。 (因此,HashMap的get()在每种情况下都不会使用equals()
。)
对于您的Location
课程,您是否碰巧实现了自己的hashCode()
版本?应谨慎实施hashCode()
方法。 Joshua Bloch描述了 Effective Java 一书中的所有细节,其中部分内容在线......我将找到指向这些示例章节的链接:Effective Java Sample Chapters。你想要第3章。
正如我在问题评论中提到的那样,_levels
变量来自哪里?我没有看到它在该方法中声明并且您的命名(下划线前缀,您是从其他语言导入该约定吗?)表明它“生活”在此方法之外。也许其他代码在执行期间会改变它?解决后请告诉我们;悬念在杀我。
答案 6 :(得分:1)
为避免出现问题,您的equals()
和hashCode()
方法应保持一致并符合要求(如其他地方所述)。
此外,hashCode()应不依赖于可变成员,否则您计算的哈希代码可能会发生变化,这会影响HashMap
的内部工作。这将导致无法从Hash*
集合中检索内容。
答案 7 :(得分:1)
在HashMap实现的源代码中占据一席之地。 get和containsKey都使用密钥对象的hasCode()和equals()方法。
唯一真正的区别,正如所指出的那样,这是一个微不足道的空检查,在比较中:
得到:
((k = e.key) == key || key.equals(k))
的containsKey:
((k = e.key) == key || (key != null && key.equals(k)))
其中e是HashMap的Entry类型。
因此,如果您没有hashCode()和/或equals()的强大实现,那么您将遇到问题。此外,如果您的密钥发生了变异(我发现您没有声明最终的类字段),您可能会遇到问题。
采用以下示例:
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));
}
}
这将打印出来:
Key:HashMapTest $ KeyCheck @ 5 Get:Success包含:true
密钥:HashMapTest $ KeyCheck @ 5 Get:Success包含:true
密钥:HashMapTest $ KeyCheck @ a Get:null包含:false
密钥:HashMapTest $ KeyCheck @ 5 Get:null包含:false
正如您所看到的,在这种情况下,可变性导致hashCode()发生更改,从而破坏了所有内容。
答案 8 :(得分: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;
}
}