【问题标题】:Java HashMap.get() returns null when I create a new instance of an object as a key当我创建对象的新实例作为键时,Java HashMap.get() 返回 null
【发布时间】:2013-12-01 00:45:17
【问题描述】:

我正在制作一个电子表格应用程序,并使用 HashMap 将数据存储在单元格中。作为关键,我使用的是 Point 类,它只有行数和列数。我遇到的问题是,如果我将 HashMap.get() 与新点一起使用,它会返回一个空值。

    HashMap<Point, String> cache = new HashMap<Point, String>();
    Point p1 = new Point(1,1);
    Point p2 = new Point(2,2);
    cache.put(p1, "Test: 1,1");
    cache.put(p2, "Test: 2,2");

    int maxRow = 2;
    int maxCol = 2;
    for (int i = 1; i <= maxRow; i++) {
        for (int j = 1; j <= maxCol; j++) {
            System.out.print(cache.get(new Point(i,j)));
            if (j < maxCol) 
                System.out.print("\t");
            if (j == maxRow)
                System.out.println("");
        }
    }

这会返回:

null     null
null     null

我可能遗漏了一些明显的东西,但我自己找不到。此外,如果您碰巧知道是否有更好的数据结构来存储来自单元格的数据,我很想听听。 提前致谢!

【问题讨论】:

  • 哈希码/等于为Point 类实现了吗?事实上,默认情况下,两个实例被认为是不同的,因为哈希码是基于对象的内存地址。
  • 啊哈,谢谢!至少它不返回空值,但现在它在每一行上返回相同的值两次,而不是一个值和一个空值。您知道可能出了什么问题吗?
  • @ThaRemo 你测试过你的新equals方法了吗?您需要检查它是否为您认为相等的对象返回 true,以及是否为您认为不同的对象返回 false。
  • @ThaRemo 你的代码(包括我的 hashcode/equals)输出良好:Test: 1,1 null null Test: 2,2 怎么了?!
  • 没关系,我在 Point 构造函数中犯了一个小错误。非常感谢!

标签: java hashmap


【解决方案1】:

要详细说明我上面的评论,您的 Point 类应该实现 hashcode 和 equals,如下所示: (存在许多实现,它只是一个有效的) 假设您的实例的变量是xy

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Point point = (Point) o;

        if (x != point.x) return false;
        if (y != point.y) return false;

        return true;
    }

    public int hashCode() {
        int result = x;
        result = 31 * result + y;
        return result;
    }

否则,如果您不覆盖这些方法,Object 的 Javadoc 可以很好地解释您的问题:

As much as is reasonably practical, the hashCode method defined by
     * class {@code Object} does return distinct integers for distinct
     * objects. (This is typically implemented by converting the internal
     * address of the object into an integer, but this implementation
     * technique is not required by the
     * Java<font size="-2"><sup>TM</sup></font> programming language.)
     *
     * @return  a hash code value for this object.
     * @see     java.lang.Object#equals(java.lang.Object)
     * @see     java.lang.System#identityHashCode
     */
    public native int hashCode();

因此,new Point(1,2) 不会被视为等于 new Point(1,2),因此永远无法从您的 Map 中检索到。

【讨论】:

    【解决方案2】:

    默认情况下,Point 的 equals 方法使用 == 即对象标识。因为 Hashmap 使用 equals 方法,所以它最终使用 == 比较键,除非它是同一个对象,否则它将返回 false。

    要解决此问题,请实现 Point 的 equalshashCode 方法,以便 point1.equals(point2) 在坐标相同时返回 true。

    【讨论】:

      【解决方案3】:

      由于您使用 Point 作为 hashmap 的键,因此您需要覆盖默认的 equals 和 hashCode 方法

      未经测试的代码

      @Override
      public boolean equals(Object obj){
      
      if (obj == null) 
          return false;
      if (obj == this) 
          return true;
      if (!(obj instanceof Point.class))
          return false;
      Point point = (Point) obj;
      return this.x == point.x && this.y == point.y;
      }
      

      【讨论】:

      • 删除那些“愚蠢”;) 最后返回:替换为:return this.x == point.x &amp;&amp; this.y == point.y
      猜你喜欢
      • 2019-08-31
      • 1970-01-01
      • 1970-01-01
      • 2013-03-13
      • 1970-01-01
      • 2012-08-08
      • 2013-05-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多