Java 如何从对象';谁的地址?

Java 如何从对象';谁的地址?,java,hash,equals,hashcode,Java,Hash,Equals,Hashcode,在Java中,我有一个子类Java3D类的Vertex。现在,Point3f根据其坐标值计算equals(),但对于我的顶点类,我想更严格一点:只有当两个顶点是同一对象时,它们才是相等的。到目前为止,一切顺利: class Vertex extends Point3f { // ... public boolean equals(Object other) { return this == other; } } 我知道这违反了equals()的约定,

在Java中,我有一个子类Java3D类的
Vertex
。现在,
Point3f
根据其坐标值计算
equals()
,但对于我的
顶点
类,我想更严格一点:只有当两个顶点是同一对象时,它们才是相等的。到目前为止,一切顺利:

class Vertex extends Point3f {

    // ...

    public boolean equals(Object other) {
        return this == other;
    }
}
我知道这违反了
equals()
的约定,但因为我只将顶点与其他顶点进行比较,所以这不是问题

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

因此,我想根据对象的地址来计算
hashCode()
,而不是从
顶点的字段来计算它。我知道
对象
类会这样做,但是我不能调用它的
hashCode()
方法,因为
Point3f
会覆盖它

所以,实际上我的问题有两个:

  • 我甚至需要这样一个浅薄的
    equals()
  • 如果是,那么,如何获取要从中计算哈希代码的对象地址
编辑:我只是想到了一些。。。我可以在创建对象时生成一个随机的
int
值,并将其用于哈希代码。这是个好主意吗?为什么(不)?

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


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

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

为给定对象返回与默认方法
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约定(对于基本对象的约定是)。。。基本上,这是基本对象方法的equals方法,因此,如果您希望使用identity equals而不是Vertex equals,这很好

至于散列代码,您确实不需要更改它,尽管接受的答案是一个很好的选择,如果您的散列表包含许多具有相同值的顶点键,则效率会更高

您不需要更改它的原因是,对于返回false的对象,哈希代码将返回相同的值是完全正确的。。。对于每个实例,始终只返回0甚至是一个有效的哈希代码。这对于哈希表是否有效是完全不同的问题。。。如果许多对象具有相同的哈希代码,则会发生更多的冲突(如果不使用哈希代码,并且有许多顶点具有相同的值,则可能会发生这种情况)


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

首先为什么要覆盖hashCode()?如果你想用其他的平等定义,你会想这么做的。比如说

公共A类{ int-id

公共布尔等于(A other){return other.id==id} public int hashCode(){return id;}

} 在这里,您需要明确的是,如果id相同,那么对象也相同,并且您重写了hashcode,因此无法执行此操作:

HashSet hash=新HashSet(); 添加(新的A(1)); 添加(新的A(1)); 并得到2个相同的(从你对平等的定义来看)A。
正确的行为是,哈希中只有一个对象,第二次写入将覆盖。

因为您使用的不是等于作为逻辑比较,而是物理比较(即,它是同一个对象),所以只有这样才能确保哈希代码返回唯一的值,就是实施你自己建议的一个变体。使用UUID为每个对象生成实际的唯一值,而不是生成随机数

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

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


这个解决的问题是,当插入hashmap时,两个独立的点对象不会相互覆盖,因为它们都具有相同的哈希。由于没有逻辑等式,因此伴随着hashCode()的重写,identityHashCode方法实际上可能导致出现这种情况。如果逻辑大小写仅替换同一逻辑点的哈希项,则使用基于系统的哈希可能会导致任意两个对象发生哈希,相等(甚至类)不再是一个因素。

实际上。。。这正是我所需要的:DIt确实违反了约定,因为Point3f.equals(顶点)可以返回true,而相反的调用总是会返回true