调查一些特殊情况,其中某些对象不应该与它们相同,并且来到这个简单的测试用例,简化了我的问题。
当使用jdk8u152在Eclipse中使用JUnit运行时,最后一个assertEquals失败,有人可以解释原因吗?
这与Set / HashSet有关,因为如果我将改为,bs 改为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);
}
答案 0 :(得分:3)
您正在改变集合的元素。这导致了未指明的行为。
来自JavaDoc:
如果将可变对象用作集合元素,则必须非常小心。如果在对象是集合中的元素的同时以影响等于比较的方式更改对象的值,则不指定集合的行为。
答案 1 :(得分:3)
您要将ao
和bo
HashMap
添加到HashSet
s as
和bs
。
稍后你通过在每个中添加一个新条目来改变ao
和bo
。
这意味着hashCode
中用于放置ao
的{{1}}不再是as
的当前hashCode
和{{1}用于在ao
中放置hashCode
的{}不再是bo
的当前bs
。
因此,hashCode
bo
无法在另一个AbstractSet
中找到一个equals
的元素,因此得出Set
不是Set
的结论等于as
。因此bs
不等于a
。
以下是b
AbstractSet
的实施情况。您可以看到它使用equals
,而containsAll
依次调用contains()
,它依赖于搜索元素的hashCode
。由于在将元素添加到hashCode
后Set
已更改,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;
}
}
如果以影响HashSet
或equals
结果的方式改变hashCode
的元素,则必须在HashSet
之前删除该元素。更新后更新并再次添加。
添加以下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);
答案 2 :(得分:-1)
这是因为HashMap的hascode实现基本上是x或键和值。如果key或value为null,则hascode将为零。因此,所有空哈希映射都将哈希码设置为零。
/*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;
}
添加键值对后,哈希码值会发生变化。