5

在 Java 中,我有一个VertexJava3D 类的子类Point3f。现在根据其坐标值进行Point3f计算,但对于我的类,我想更严格:两个顶点只有在它们是同一个对象时才相等。到现在为止还挺好:equals()Vertex

class Vertex extends Point3f {

    // ...

    public boolean equals(Object other) {
        return this == other;
    }
}

我知道这违反了 的合同equals(),但是因为我只会将顶点与其他顶点进行比较,所以这不是问题。

现在,为了能够将顶点放入 aHashMap中,该hashCode()方法必须返回与 一致的结果equals()。它目前是这样做的,但它的返回值可能基于 的字段Point3f,因此会为Vertex具有相同坐标的不同对象提供哈希冲突。

因此,我想基于对象的地址,而不是从的字段hashCode()中计算它。Vertex我知道这个Object类是这样做的,但我不能调用它的hashCode()方法,因为Point3f它会覆盖它。

所以,实际上我的问题是双重的:

  • 我什至要这么浅equals()
  • 如果是,那么,我如何获取对象的地址来计算哈希码?

编辑:我只是想到了一些东西......我可以int在对象创建时生成一个随机值,并将其用于哈希码。这是一个好主意吗?为什么不)?

4

7 回答 7

10

使用 System.identityHashCode() 或使用 IdentityHashMap。

于 2008-09-24T18:29:26.190 回答
1

System.identityHashCode()为给定对象返回与默认方法返回的相同的哈希码hashCode(),无论给定对象的类是否覆盖hashCode()

于 2008-09-24T18:31:13.113 回答
0

即使这个答案可能更好,您也可以使用委托。


class Vertex extends Point3f{
   private final Object equalsDelegate = new Object();
   public boolean equals(Object vertex){
      if(vertex instanceof Vertex){
         return this.equalsDelegate.equals(((Vertex)vertex).equalsDelegate);
      }
      else{
         return super.equals(vertex);
      }
   }
   public int hashCode(){
      return this.equalsDelegate.hashCode();
   }
}
于 2008-09-24T18:38:51.347 回答
0

仅供参考,您的 equals 方法不违反 equals 合同(对于基本 Object 的合同)......这基本上是基本 Object 方法的 equals 方法,所以如果你想要身份 equals 而不是 Vertex equals,那就是美好的。

至于哈希码,您实际上不需要更改它,尽管接受的答案是一个不错的选择,如果您的哈希表包含许多具有相同值的顶点键,效率会更高。

您不需要更改它的原因是因为哈希码将为等于返回 false 的对象返回相同的值是完全没问题的......它甚至是一个有效的哈希码,每次只返回 0实例。这对哈希表是否有效是完全不同的问题......如果您的许多对象具有相同的哈希码(如果您单独留下哈希码并且有很多顶点,可能就是这种情况)具有相同的值)。

当然,请不要接受这个作为答案(你选择的更实用),我只是想给你一些关于哈希码和等于的背景信息;-)

于 2008-09-24T18:44:10.350 回答
0

为什么首先要覆盖 hashCode() ?如果您想使用其他一些平等定义,您会想要这样做。例如

公共类 A { int id;

public boolean equals(A other) { return other.id==id} public int hashCode() {return id;}

您想清楚的是,如果 id 相同,则对象相同,并且您覆盖哈希码,因此您不能这样做:

HashSet hash=new HashSet(); hash.add(新 A(1)); hash.add(新 A(1)); 并获得 2 个相同的(从您对平等的定义的角度来看)A。正确的行为是您在哈希中只有 1 个对象,第二次写入将覆盖。

于 2008-09-24T19:43:44.297 回答
0

由于您不是使用等于作为逻辑比较,而是使用物理比较(即,它是同一个对象),所以保证哈希码返回唯一值的唯一方法是实现您自己建议的变体。不是生成随机数,而是使用 UUID 为每个对象生成一个实际的唯一值。

System.identityHashCode() 在大多数情况下都可以工作,但不能保证,因为 Object.hashCode() 方法不能保证为每个对象返回唯一值。我已经看到发生了边缘情况,它可能取决于 VM 实现,这不是您希望代码依赖的东西。

Object.hashCode() 的 javadocs 摘录:尽可能合理地实用,由 Object 类定义的 hashCode 方法确实为不同的对象返回不同的整数。(这通常通过将对象的内部地址转换为整数来实现,但 JavaTM 编程语言不需要这种实现技术。)

这个解决的问题是两个独立的点对象在插入哈希图中时不会相互覆盖,因为它们都具有相同的哈希值。由于没有逻辑上的等号,伴随着对 hashCode() 的覆盖,identityHashCode 方法实际上会导致这种情况发生。在逻辑案例只会替换相同逻辑点的哈希条目的情况下,使用基于系统的哈希可能会导致它与任何两个对象一起发生,相等(甚至类)不再是一个因素。

于 2008-09-24T22:43:23.600 回答
-2

函数 hashCode() 继承自 Object 并且完全按照您的意图工作(在对象级别,而不是坐标级别)。应该没有必要改变它。

至于您的 equals 方法,甚至没有理由使用它,因为您可以在代码中执行 obj1 == obj2 而不是使用 equals,因为它是用于排序和类似的,比较坐标更有意义。

于 2008-09-24T18:27:14.683 回答