在Java中,我有一个子类 Vertex Java3D 类的 Point3f. 。现在 Point3f 计算 equals() 基于其坐标值,但对于我来说 Vertex 我想更严格的班级:仅当两个顶点是同一个对象时,它们才相等。到目前为止,一切都很好:

class Vertex extends Point3f {

    // ...

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

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

现在,能够将顶点放入 HashMap, , 这 hashCode() 方法必须返回与以下内容一致的结果 equals(). 。它目前这样做,但可能将其返回值基于 Point3f, ,因此会给出不同的哈希冲突 Vertex 具有相同坐标的物体。

因此我想根据 hashCode() 在对象的地址上,而不是从 Vertex的字段。我知道 Object 类执行此操作,但我不能调用它 hashCode() 方法因为 Point3f 覆盖它。

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

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

编辑:我刚刚想到一件事...我可以生成一个随机数 int 对象创建时的值,并将其用作哈希码。这是一个好主意吗?为什么不)?

有帮助吗?

解决方案

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

其他提示

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

即使这样你也可以使用委托 回答 可能更好。


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();
   }
}

仅供参考,您的 equals 方法不会违反 equals 契约(对于基本对象的契约而言)......这基本上是基本 Object 方法的 equals 方法,因此如果您想要标识 equals 而不是 Vertex equals,那很好。

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

您不需要更改它的原因是因为对于等于返回 false 的对象,哈希代码将返回相同的值是完全可以的......它甚至是一个有效的哈希码,对于每个实例始终返回 0。这对于哈希表是否有效是完全不同的问题......如果许多对象具有相同的哈希码(如果您单独保留哈希码并且有许多具有相同值的顶点,则可能会出现这种情况),您将会遇到更多的冲突。

当然,请不要接受这个答案(您选择的更实用),我只是想为您提供更多有关哈希码和等于的背景信息;-)

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

公共类A {int ID;

public boolean等于(另一个){return other.id == id} public int hashcode(){return ID;}

}您想清楚地表明,如果ID相同,那么对象是相同的,并且您覆盖了hashcode,以便无法执行此操作:

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

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

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

摘自 Object.hashCode() 的 javadoc:在相当实用的情况下,Object 类定义的 hashCode 方法确实为不同的对象返回不同的整数。(这通常是通过将对象的内部地址转换为整数来实现的,但 JavaTM 编程语言不需要这种实现技术。)

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

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top