由于" hashCode()" HashMap.get()没有返回正确的值。

时间:2016-12-14 13:52:37

标签: java hash hashmap equals hashcode

我目前正在使用地图编辑器开发TD游戏。显然,你可以保存并加载这些地图(或者至少应该能够)。 问题是:在某个时刻,我在.get()上呼叫HashMap。不幸的是,应该是相同的(逻辑方面的)键不是相同的对象(就参考而言),并且,根据我以前的谷歌研究,覆盖他们的.equals方法是不够的,因为他们仍然会使用.hashCode()返回不同的哈希值(我验证过,他们会返回不同的哈希值,而.equals确实返回true)。
(另一方面,由于HashMap.get(key)的javadoc只表明它们必须相等,因此相当令人困惑)

更具体地说,HashMap包含我的类Path的实例作为键,并且应该返回相应的敌人列表(= value)。

Path的简短版本(没有getter等):

public class Path
{
    private List<Tile> tiles = new ArrayList<>();
    @Override
    public boolean equals(Object obj) {
        //code comparing the two paths
    }
    @Override
    public int hashCode() {
        //what I still need to implement. ATM, it returns super.hashCode()
    }
}

public class Tile
{
    private int x;
    private int y;
    //constructor
    //overrides equals
    //getters & some convenience methods
}

现在如果两个Path相等,我希望它们返回相同的哈希码,以便HashMap返回正确的敌人列表。 (我确保不能添加两个相同的路径)。

现在我的问题:

你建议

  1. 使用一些外部库生成哈希
  2. 我编写自己的计算哈希的实现,或
  3. 别的东西
  4. 请注意,我更愿意避免将HashMap更改为其他类型的地图,如果这样可以帮助解决问题。

2 个答案:

答案 0 :(得分:2)

您肯定需要实施与hashCode一致的equals。 IDE通常可以正常生成hashCodeequals。另请考虑Objects.equals(...)Objects.hash(...)

关于在Path中使用HashMap作为键的一个警告。您必须使该类不可变,以使其可靠地工作。或者至少确保密钥的hashCode不会改变。否则,即使使用相同或相同的密钥,您也可能无法获得数据。

答案 1 :(得分:1)

List有一个有用的方法,方便地命名为list.hashCode()。这将计算列表中所有元素的hashCode。所以你还必须为Tile实现hashCode,它可能包含一些原始字段等。

e.g。

 @Override
    public int hashCode() {
         return tiles != null ? tiles.hashCode() : 0;
    }

查看文档here

  

int hashCode()
  返回此列表的哈希码值。列表的哈希码被定义为以下计算的结果:

  int hashCode = 1;
  for (E e : list)
      hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
  

根据list1.equals(list2)的一般合同的要求,这可确保list1.hashCode()==list2.hashCode()隐含任意两个列表list1list2 Object.hashCode()