Java 如何从对象';谁的地址?
在Java中,我有一个子类Java3D类的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()的约定,
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