When does HashSet 'add' method calls equals?
我在hashset比较中做了这个测试,没有调用equals。
当遥远=错误时,我想考虑平等。(用于检查两点距离的功能)
完整的可编译代码,您可以测试它,并说明为什么在本例中不调用equals。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class TestClass {
static class Posicion
{
private int x ;
private int y ;
@Override
public boolean equals (Object obj ) {
if (obj == null) {
return false;
}
if (getClass () != obj. getClass()) {
return false;
}
final Posicion other = (Posicion ) obj ;
if ( farAway (this. x, other. x, this. y, other. y, 5)){
return false;
}
return true;
}
@Override
public int hashCode () {
int hash = 7; hash = 59 * hash + this. x; hash = 59 * hash + this. y;
return hash ;
}
Posicion (int x0, int y0 ) {
x =x0 ;
y =y0 ;
}
private boolean farAway (int x, int x0, int y, int y0, int i ) {
return false;
}
}
public static void main (String[] args ) {
HashSet <Posicion > test =new HashSet <>();
System. out. println("result:"+test. add(new Posicion (1, 1)));
System. out. println("result:"+test. add(new Posicion (1, 2)));
}
} |
编辑
-是否有方法强制将哈希集添加到调用equals?
- equals中的farAway调用是什么?你的学生违反了hashCode和equals之间的合同!
- @在这里你有一个完整的测试,遥远的只是返回错误,以确保对象被平等对待,但平等从来没有被调用。
- 您必须遵守hashCode和equals之间的合同。这意味着当您的equals方法返回true时,您的hashCode必须返回相同的整数值。这在你的代码中不会发生。
- @阿隆索多明格斯我明白了,我一直在努力避免散列码,而只使用等号,我现在明白了这是不可能的,谢谢你坚持与合同中断,那么现在我知道什么时候不叫等号,我仍然不知道什么时候才真正叫等号。
- @Hern&neche:你似乎想做的事情可能非常棘手——不仅你必须遵守hashCode()的合同,而且还必须遵守equals()的合同。equals()必须是可传递的。因此,如果您返回true,对于a和b,因为它们彼此接近,而b和c,因为它们彼此接近,那么在检查a和c之间的相等性时,如果它们恰好不接近,您将遇到问题。我认为您需要设计一个容器/数据结构,而不是标准散列集来做您想做的事情(如果您想做的甚至是一个好主意的话)。
- @Michaelburr Bold Insight+1(和有趣的括号),好点,欧几里得距离不可传递,加上任何阈值,a可以"接近"b,b"接近"c,但我们不能就a说任何关于c的话,它可以"接近"或"不",那么"等于"应该与所有元素(它没有的东西)进行比较。我知道,它不会破坏我的代码,因为这里有一个加载顺序,它不是欧几里得距离,但它是一个非常有用的注释,谢谢。
如果散列码不同,则无需调用equals(),因为它保证返回false。
这是根据关于equals()和hashCode()的总合同:
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
号
现在你们班违反了合同。你需要解决这个问题。
- 我需要平等的人
- 那么散列码就不应该是相同的。
- 这就是问题所在,hashcode不一样,也不调用equals。
- @hern&225;neche您的套装中是否已有物品?如果加上第一个,可能不会调用equals(因为没有什么可与之比较的)。
- @赫恩&225;内切:这没有道理。hashset调用equals()以确保集合中不存储重复的对象。如果它可以确保不调用equals(例如,因为集合中还没有任何内容,或者集合中没有其他对象具有相同的哈希代码),为什么它会调用equals()?还有其他物体?
- @塞巴斯蒂安克雷斯曼斯基是的,当然,你可以测试这个例子。
- @hern&225;neche:这两个对象返回不同的哈希代码。根据hashCode()的合同,图书馆(或任何人)可以认为对象不相等——如果散列码不同,就不需要调用equals()。
- @Michaelburr的观点是,如果hashcode不同,那么就不需要调用equals,如果hashcode相等,那么就不需要调用equals,finally equals永远不会被调用,所以这个问题的答案应该是,equals永远不会被调用,不管你在它里面放了什么,或者在hashcode里面放了什么。
- @赫恩&225;内切:那不是真的。使hashCode()始终返回0并查看会发生什么。
- @hern&n:如果散列码不同,则对象不同,不调用equals。如果哈希代码相同,则对象可能相等,因此调用equals(object)以确保它们相同。
- @Jarnbjo你是对的,我测试错了,谢谢!
如果你想一直叫equals(),就一定要回来,比如说,hashCode()里的0。这样,所有项目都具有相同的哈希代码,并且只与equals()进行比较。
1 2 3
| public int hashCode() {
return 0;
} |
号
- 它不起作用,请测试我在问题中输入的代码(如果您想返回相同的hashcode),但没有调用equals,如果hashcode返回相同的值,那么hashmap将对象视为不同的对象,那么就不需要调用equals。
- 那你能解释一下你期望的结果吗?您的代码应该产生什么输出?
- 功能是拒绝添加两个相似的对象,在这种情况下,平面上的两个点彼此接近,但我可以通过数百种方式达到相同的功能,问题不在于解决单个问题,而是要了解哈希图实际调用equals的时间,或者如果从未通过它调用equals。
- 我刚刚测试了我的代码,它按预期工作。调用test.add(new Posicion(1,2)返回false,因为调用equals()。这是怎么回事?
- 我的测试错了,现在都清楚了,谢谢
- 使用这个技巧有什么缺点吗?
听起来哈希集不适合你。听起来你想要一种比较两个位置的自定义方式。而不是说"两个位置完全相同吗?".相反,您应该使用带有比较器的treeset。这样,您就可以编写一个"iswithinRangeComparator",并在那里检查范围。
如上所述,当对象相等时,它们的哈希代码也应该相同。您可以像下面这样对散列代码计算进行简单的修正。
1 2 3 4 5 6 7
| public int hashCode() {
int hash = 7; hash = 59 * hash + this.x; hash = 59 * hash + this.y;
boolean faraway=farAway(this.x, other.x, this.y, other.y,5);
hash=59*hash+(faraway?1:0); //include faraway also as part of hashcode computation
return hash; |
}
- 当然不可能使用hashcode()中的farraway方法,因为您没有其他对象可供比较。
- @你说得对
- @hashet的工作原理是比较对象的hashcode。如果哈希代码不同,则无需调用equals(),因为对象被认为是不同的,两个对象都将放入哈希集中。只有当哈希代码相同时才调用equals(),在这种情况下,将调用equals()来比较值
- @Zenil不,如果hashcodes相同,就不会调用equals,因为它意味着对象是相同的!那么,我仍然想知道,什么时候叫平等?
- @herman,@jarnbjo:faraway()接受5个参数。为什么需要与另一个对象进行比较?您需要传入的其他对象的x和y。可以在hashcode中调用faraway(),就像在equals()中调用一样。我是否缺少某些内容?
- @泽尼尔:是的,你错过了什么。如果没有其他对象,您希望从何处获取参数other.x和other.y?
- @杰恩乔:明白了。谢谢