一致的Equals()结果,但不一致的TreeMap.containsKey()结果
我有以下对象Node
:
private class Node implements Comparable(){ private String guid(); ... public boolean equals(Node o){ return (this == o); } public int hashCode(){ return guid.hashCode(); } public int compareTo(Node o){ return (this.hashCode() - o.hashCode()); } ... }
我在以下TreeMap
使用它:
TreeMap<Node, TreeSet> nodes = new TreeMap<Node, TreeSet>();
现在,树图在名为Graph
的类中使用,以存储当前在图中的节点,以及它们的一组边(来自类Edge
)。 我的问题是当我尝试执行时:
public containsNode(n){ for (Node x : nodes.keySet()) { System.out.println("HASH CODE: "); System.out.print(x.hashCode() == n.hashCode()); System.out.println("EQUALS: "); System.out.print(x.equals(n)); System.out.println("CONTAINS: "); System.out.print(nodes.containsKey(n)); System.out.println("N: " + n); System.out.println("X: " + x); System.out.println("COMPARES: "); System.out.println(n.compareTo(x)); } }
我有时会得到以下信息:
HASHCODE:true EQUALS:true CONTAINS: false N:foo X:foo比较:0
任何人都知道我做错了什么? 我还是新手,所以如果我忽略了一些简单的事情,我会事先道歉(我知道hashCode()
对于TreeMap
并不重要,但我想我会把它包括在内)。
edit1:添加了compareTo()
方法信息。
这里有一些问题。
- 您没有覆盖
Object.equals
。 使用@Override public boolean equals(Object obj)
。 -
compareTo
存在潜在的整数溢出错误。 这可能是导致此特定错误的原因。 它会扰乱排序,因此搜索可能不会成功。 -
compareTo
方法声称如果哈希码恰好匹配,则两个实例是相等的(可能是难以捕获的错误,无需代码审查)。
对于整数溢出问题,请参阅问题为什么我的简单比较器坏了?
TreeSet不使用equals()来确定相等性。 它使用Comparator(或Comparable)代替。 为了使其正常工作,您必须遵循equals规则的一致性 :
“当且仅当c.compare(e1,e2)== 0具有与e1.equals(e2)相同的布尔值时,比较器c对一组元素S施加的排序被认为与等于一致。 S“中的e1和e2。
我猜你没有遵循这个规则(你没有提供compareTo方法的实现)。 如果未遵循规则,则树集将不具有Set的正常行为。
有关详细信息,请参阅http://eyalsch.wordpress.com/2009/11/23/comparators/ 。
– 编辑 –
现在您提供了compareTo实现,很明显它有一个缺陷。 对于不相等的2个节点(并且具有相同的哈希码),它可以返回0。 因此,您无法在TreeSet中添加具有相同哈希码的2个项目!
检查比较器。
containsKey()
调用可能依赖于比较器的getEntry()
。 如果它被破坏,你可能会得到不一致的结果。