我最近一直在使用Java的HashMap,并且遇到了一些有趣的行为。我目前正在使用它来存储具有多个字段的键/值对象。为此,我重写了hashCode()和equals(),如下所示:
public final class TransitionState {
private String mStackSymbol;
private String mTransitionSymbol;
private int mState;
private static final int HASH_SEED = 7; //Should be prime
private static final int HASH_OFFSET = 31;
//Constructor and getter methods here
public boolean equals(TransitionState other) {
//Check that we aren't comparing against ourself
if (this == other) {
return true;
}
//Check that we are not comparing against null
if (other == null) {
return false;
}
//Check fields match
if ((mState == other.getState()) &&
(mTransitionSymbol.equals(other.getTransitionSymbol())) &&
(mStackSymbol.equals(other.getStackSymbol()))) {
return true;
} else {
return false;
}
}
public int hashCode() {
int intHash = HASH_SEED;
//Sum hash codes for individual fields for final hash code
intHash = (intHash * HASH_OFFSET) + mState;
intHash = (intHash * HASH_OFFSET) + (mTransitionSymbol == null ? 0 : mTransitionSymbol.hashCode());
intHash = (intHash * HASH_OFFSET) + (mStackSymbol == null ? 0 : mStackSymbol.hashCode());
return intHash;
}
}
现在,我可以毫无问题地将项目放入地图中。然而,检索它们是另一回事。每当我尝试从HashMap中获取get()时,都会返回NULL。我编写了一些测试代码来迭代Map和打印值,这是令我感到困惑的地方,因为我的关键对象的hashCode()与我在map中的相同,并且与已知值的相等性返回true。示例输出如下(参见表格底部的第四个转换):
Transition Table:
State Symbol Stack Move
--------------------------
1, a, b, (1, pop) with key hashcode 212603 and value hashcode 117943
0, b, a, (0, pop) with key hashcode 211672 and value hashcode 117912
1, b, z, (1, push) with key hashcode 212658 and value hashcode 3459456
0, a, b, (0, pop) with key hashcode 211642 and value hashcode 117912
1, a, z, (0, push) with key hashcode 212627 and value hashcode 3459425
0, a, a, (0, push) with key hashcode 211641 and value hashcode 3459425
0, a, z, (0, push) with key hashcode 211666 and value hashcode 3459425
0, b, z, (1, push) with key hashcode 211697 and value hashcode 3459456
1, b, a, (1, pop) with key hashcode 212633 and value hashcode 117943
1, b, b, (1, push) with key hashcode 212634 and value hashcode 3459456
ababba
Transition from (0, a, z) with hashcode 211666
transition.equals(new TransitionState(0, "a", "z")) = true
HashMap containsKey() = false
Transition not found
false
正如您所看到的,密钥将哈希码与地图中的条目匹配,但我被告知它不存在。我尝试调试HashMap的containsKey()方法,该方法执行get(),检查是否为NULL。进入get()会显示循环,只返回NULL之前只运行一次。
那么,这是一个HashMap问题(可能不是)还是(更有可能)我可能做错了什么?提前感谢您的帮助。
答案 0 :(得分:19)
你没有正确覆盖 equals
......你需要
public boolean equals(Object other)
目前你只是重载。
基本上真实覆盖仍然可以完成与现有覆盖相同的工作,但首先进行测试:
if (!(other instanceof TransitionState))
{
return false;
}
TransitionState otherState = (TransitionState) other;
// Now do the rest of the comparison
请注意,在这种情况下,您不需要检查null,因为它会导致instanceof
测试失败。
现在Java允许你添加一个注释来告诉编译器你真的试图覆盖父方法:
@Overrides
public boolean equals(Object other)
现在,编译器会告诉您是否在名称中输入错误或者签名错误。
答案 1 :(得分:2)
乔恩是对的。此外,您应该执行以下操作:
让你的实例变量最终:
private final String mStackSymbol;
private final String mTransitionSymbol;
private final int mState;
如果您不能这样做,请确保在将项目放入地图后不更改这些变量的值。如果在将它们放入地图后状态发生变化,您将无法再将它们取出(至少不是原始值)。