奇怪的等于()结果与地图/设置对象图



调查一种特殊情况,其中某些对象不等于应有的位置,并得出了这个简单的测试用例,简化了我的问题。

当在 Eclipse 中使用 jdk8u152 运行它时,最后一个断言等于失败,谁能解释为什么?

这是Set/HashSet的东西,因为如果我将as,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);
}

你正在改变集合的元素。 这会导致未指明的行为。

来自JavaDoc:

如果将可变对象用作集合元素,则必须格外小心。如果对象的值以影响等于比较的方式更改,而对象是集中的元素,则不指定集合的行为。

您正在将aoboHashMaps添加到HashSetasbs中。

稍后,您可以通过在每个条目中放置一个新条目来改变aobo

这意味着用于将ao放置在as中的hashCode不再是ao的当前hashCode,而用于将bo放置在bs中的hashCode不再是bo的当前hashCode

结果,AbstractSetequals不能在另一个Set中定位一个Set的元素,所以它得出结论as不等于bs。因此a不等于b

这是AbstractSetequals的实现。你可以看到它使用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;
}
}

如果以影响equalshashCode结果的方式更改HashSet的元素,则必须在更新之前从HashSet中删除该元素,并在更新后再次添加该元素。

添加以下removeadd调用将导致最终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);

这是因为HashMap的hascode实现基本上是键和值的x-or。如果键或值为空,则 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;
}

添加键值对后,哈希码值会发生变化。

相关内容

  • 没有找到相关文章

最新更新