包含自身作为值的地图;

问题描述 投票:7回答:4

直接来自this java doc:

这种禁令的一个特例是地图不允许将自己作为关键词包含在内。虽然允许映射将自身包含为值,但建议极其谨慎:equals和hashCode方法不再在这样的映射上很好地定义。

为什么hashcode和equals不再在这样的地图上定义好?

java dictionary equals hashcode
4个回答
2
投票

Java Docs段落的完整引用是:

注意:如果将可变对象用作映射键,则必须非常小心。如果在对象是地图中的键的情况下以影响等于比较的方式更改对象的值,则不指定映射的行为。这种禁令的一个特例是地图不允许将自己作为关键词包含在内。虽然允许映射将自身包含为值,但建议极其谨慎:equals和hashCode方法不再在这样的映射上很好地定义。

AbstractMap.hashCode()方法使用映射中键值对的哈希码来计算哈希码。因此,每次修改映射时,从此方法生成的哈希码都会更改。

哈希码用于计算存储桶以放置新条目。如果映射本身用作密钥,那么每次更新/删除/修改新条目时计算的存储桶都会不同。因此,将来使用映射作为键的查找很可能会失败,因为从哈希码计算出不同的桶。 Future puts可能无法检测到密钥已经存在于映射中,然后允许具有相同密钥的多个条目(但在不同的桶中)


5
投票

相关部分形成AbstractMap.equals,大多数Map实现都使用它:

            Iterator<Entry<K,V>> i = entrySet().iterator();
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                K key = e.getKey();
                V value = e.getValue();
                if (value == null) {
                    if (!(m.get(key)==null && m.containsKey(key)))
                        return false;
                } else {
                    if (!value.equals(m.get(key))) // would call equals on itself.
                        return false;
                }
            }

将地图添加为值将导致无限循环。


1
投票

如果相同的键映射相同的值,则两个映射相等。 (在某些实现中。)因此,为了检查相等性,应检查每个成员的相等性。

因此,如果地图包含自身,您将获得无限递归的相等性检查。

哈希也是如此,因为这些可以根据地图中元素的哈希值来计算。

例:

Map<Int, Object> ma;
Map<Int, Object> mb;
Map<Int, Object> mc;

ma.put(1, ma);
ma.put(2, mb);
mc.put(1, ma);
mc.put(2, mb);

作为人类,我们可以看到mamc与定义相同。计算机将在两个地图中看到mb(空地图)上的2个地图,这很好。它将在mc和ma中的另一个地图上看到1个地图。它检查这些地图是否相等。为了确定这一点,它再次检查1的两个值是否等于。然后再次。

请注意,并非所有实现都是如此。某些实现可能会检查内存中保存对象的位置是否相等,但是每次递归检查都会无限循环。


0
投票

试着解释一下:

equals方法将迭代两个Maps并调用每个键的equals方法和map的值。因此,如果地图包含自己,您将无限期地继续调用equals方法。

哈希码也会发生同样的事情。

来源:AbstractMap类的源代码

© www.soinside.com 2019 - 2024. All rights reserved.