[英]Weird equals() result with Map/Set object graph
Investigating a special case where some objects didn't equal as they should and came to this simple test case that simplifies my issue. 研究一种特殊情况,其中某些对象不符合其应有的条件,并进入了这个简单的测试用例,简化了我的问题。
When running this with JUnit in Eclipse with jdk8u152 the last assertEquals fails, can anyone explain why? 在带有jdk8u152的Eclipse中使用JUnit运行此命令时,最后一个assertEquals失败,有人可以解释为什么吗?
It's something with Set/HashSet because if I change as,bs to be ArrayList's instead the final assertEquals goes through. 这与Set / HashSet有关,因为如果我将as更改为 ArrayList,则最终的assertEquals将通过。
@Test
public void test()
{
String list = "list";
String object = "object";
String value = "value";
Map<String, Object> a = new HashMap<>();
Map<String, Object> b = new HashMap<>();
assertEquals(a, b);
Set<Object> as = new HashSet<>();
Set<Object> bs = new HashSet<>();
a.put(list, as);
b.put(list, bs);
assertEquals(a, b);
Map<String, Object> ao = new HashMap<>();
as.add(ao);
Map<String, Object> bo = new HashMap<>();
bs.add(bo);
assertEquals(a, b);
ao.put(object, value);
bo.put(object, value);
assertEquals(a, b);
}
You're mutating the elements of the sets. 您正在变异集合的元素。 That leads to unspecified behaviour. 这导致了未指明的行为。
Great care must be exercised if mutable objects are used as set elements. 如果将可变对象用作集合元素,则必须格外小心。 The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set. 如果对象的值更改为影响相等比较的方式,而该对象是集合中的元素,则不指定集合的行为。
You are adding ao
and bo
HashMap
s to the HashSet
s as
and bs
. 你加入ao
和bo
HashMap
年代到HashSet
小号as
和bs
。
Later you mutate ao
and bo
by putting a new entry in each of them. 稍后,通过在每个bo
放置一个新条目来对ao
和bo
进行突变。
This means that the hashCode
that was used to place ao
in as
is no longer the current hashCode
of ao
, and the hashCode
that was used to place bo
in bs
is no longer the current hashCode
of bo
. 这意味着hashCode
这是用来放置ao
在as
不再是当前hashCode
的ao
,以及hashCode
这是用来放置bo
在bs
不再是当前hashCode
的bo
。
As a result, AbstractSet
's equals
cannot locate the element of one Set
in the other Set
, so it concludes that as
is not equal to bs
. 其结果是, AbstractSet
的equals
无法找到一个的元件Set
在另一个Set
,所以它的结论是, as
不等于bs
。 As a result a
is not equal to b
. 结果a
不等于b
。
Here's the implementation of AbstractSet
's equals
. 这是AbstractSet
equals
。 You can see that it uses containsAll
, which in turns calls contains()
, which relies on the hashCode
of the searched element. 您可以看到它使用了containsAll
,它依次调用contains()
,后者依赖于搜索到的元素的hashCode
。 Since that hashCode
has changed after the element was added to the Set
, contains()
doesn't find the element. 由于在将元素添加到Set
之后该hashCode
发生了变化, contains()
找不到该元素。
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection<?> c = (Collection<?>) o;
if (c.size() != size())
return false;
try {
return containsAll(c);
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
}
If you mutate an element of a HashSet
in a way that affects the result of equals
or hashCode
, you must remove the element from the HashSet
prior to the update and add it again after the update. 如果以影响equals
或hashCode
结果的方式对HashSet
的元素进行变异,则必须在更新之前从HashSet
删除该元素,然后在更新后再次添加它。
Adding the following remove
and add
calls will cause a
to be equal to b
in the end: 添加以下remove
和add
调用将最终使a
等于b
:
....
assertEquals(a, b);
bs.remove (bo); // added
as.remove (ao); // added
ao.put(object, value);
bo.put(object, value);
as.add (ao); // added
bs.add (bo); // added
assertEquals(a, b);
That is because of the hascode implementation of HashMap which is basically x-or of key and value. 这是因为HashMap的hascode实现基本上是键和值的x或。 If key or value is null then hascode will be zero. 如果key或value为null,则hascode将为零。 Hence all empty hashmaps will have hashcode as zero. 因此,所有空哈希图的哈希码都将为零。
/*hashcode of HashMap*/
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
/*hashcode of object*/
public static int hashCode(Object o) {
return o != null ? o.hashCode() : 0;
}
Upon adding key value pairs the hashcode value changes. 在添加键值对后,哈希码值会更改。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.