我有一个自定义类 MarioState,我想在 HashMap 中使用它。该类代表马里奥游戏的状态空间中的可能状态。下面是 MarioState 类的简化版本。
在我的 HashMap 中,我想存储这些状态。然而,在比较两个 MarioState 时,并不需要考虑 MarioState 中的属性。例如,如果一个 MarioState 将卡住属性设置为 true 且距离为 30,而另一个 MarioState 也将卡住属性设置为 true 但距离值不同(例如 20),那么它们仍然应被视为相同。
我知道要在我的 HashMap 中工作,我必须实现 .equals() 和 .hashcode() 方法,这就是我所做的(让它们由 InteliJ IDE 自动生成)。
public class MarioState{
// Tracking the distance Mario has moved.
private int distance;
private int lastDistance;
// To keep track of if Mario is stuck or not.
private int stuckCount;
private boolean stuck;
public MarioState(){
stuckCount = 0;
stuck = false;
distance = 0;
lastDistance = 0;
}
public void update(Environment environment){
// Computing the distance
int tempDistance = environment.getEvaluationInfo().distancePassedPhys;
distance = tempDistance - lastDistance;
lastDistance = tempDistance;
// If Mario hasn't moved for over 25 turns then this means he is stuck.
if(distance == 0){
stuckCount++;
} else {
stuckCount = 0;
stuck = false;
}
if(stuckCount > 25){ stuck = true; }
}
public float calculateReward(){
float reward = 0f;
reward += distance * 2;
if(stuck){ reward += -20; }
return reward;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MarioState that = (MarioState) o;
if (stuck != that.stuck) return false;
return true;
}
@Override
public int hashCode() {
return (stuck ? 1 : 0);
}
}
然而,问题是,在运行代码时,某些键被认为是不同的,而它们不应该根据它们的 .equals() 和 .hashcode() 函数。什么可能导致这种情况?我是不是忘记了什么?
在HashMap中插入状态时使用的代码(如果需要可以提供附加信息):
public float[] getActionsQValues(MarioState state){
if(!table.containsKey(state)) {
float[] initialQvalues = getInitialQvalues(state);
table.put(state, initialQvalues);
return initialQvalues;
}
return table.get(state);
}
我处于 Debug模式时的屏幕截图显示我的表包含两个具有不同值的键,但键本身是相同的(但在 HashMap 中它被认为是不同的)。
最佳答案
您的哈希码计算和相等性比较都基于卡住
- 但这可能会随着时间的推移而改变。
如果您在将对象添加为 HashMap 中的键后对其进行变异,从而使哈希码发生变化,那么当您稍后请求它时将找不到该键 - 因为存储的哈希码第一次添加的 key 将不再与其当前的哈希码相同。
尽可能避免使用可变对象作为映射中的键(即使是不使用哈希码的 TreeMap
,如果您以以下方式更改对象,也会出现相同的问题:会改变相对顺序)。如果您必须使用可变对象作为映射中的键,则应避免在将它们添加为键后更改它们。
关于java - HashMap 的 ContainsKey 不适用于自定义类作为键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23173876/