如何覆盖两个<string,object =“”>?</string,>的映射的等于

时间:2013-12-14 07:27:16

标签: java map equals

我有一个具有Map&lt; String,Object&gt;的类。字段(键是字符串,值是已正确实现“等于”方法进行比较的对象)。

我想以这样的方式覆盖此类的equals,如果Maps在键和值之间具有相等的映射,则只返回true。

这是我的尝试:

// Assumes that the Object values in maps have correctly implemented the equals method.
private boolean mapsEqual(Map<String, Object> attributes) 
{
    if (this.attributes_.keySet().size() != attributes.keySet().size() ||
        this.attributes_.values().size() != attributes.values().size())
        return false;
    for (String key : attributes.keySet()) {
        if (!this.attributes_.keySet().contains(key))
            return false;
        if (!this.attributes_.get(key).equals(attributes.get(key)))
            return false;
    }
    return true;
}

但是,当多次添加相同的键或从映射中删除键时,此实现失败(值的大小测试失败,因为它们计算重复项,并且在删除值时不会调整大小。)

似乎我的情况应该足够常见,以找到与我的案件相关的信息,但我找不到任何信息。这种情况是否有任何遗留代码或广泛接受的解决方案?任何帮助或工作解决方案表示赞赏。

2 个答案:

答案 0 :(得分:1)

即使我不是100%确定它能解决你的问题(但它根本不适合评论),我会把它作为答案。

首先,重复我的评论:Map界面禁止地图有重复键或每个键有多个值。因此,任何适当的实施(例如java.util.HashMap)都不允许这样做。通常情况下,如果发生这种情况,他们只会替换该值。

此外,对我而言,equals的规范似乎正在做你想要的。同样,正确的实现必须符合该规范。

所以,这里有什么意义:如果你正在编写自己正在实现Map的类,那么它就不能允许重复键(像get这样的方法就没有意义了)。如果您使用的是HashMap等内置实现,则无论如何都会替换这些值。

现在您说您遇到了keySet()values()的尺寸问题。我认为你应该添加会导致这种行为的示例代码。以下工作对我来说很好:

Map<String, String> map = new HashMap<String, String>();
map.put("Foo", "Bar");

System.out.println(map.keySet().size()); // 1
System.out.println(map.values().size()); // 1

map.put("Foo", "Baz"); // the HashMap will merely replace the old value

System.out.println(map.keySet().size()); // still 1
System.out.println(map.values().size()); // still 1

删除密钥当然会改变大小。到目前为止,根据您的解释,我不认为您认为这是一个问题。

关于equals,您可能只想查看HashMap的实现,可以找到 here

public boolean equals(Object o) {
    if (o == this)
        return true;

    if (!(o instanceof Map))
        return false;
    Map<K,V> m = (Map<K,V>) o;
    if (m.size() != size())
        return false;

    try {
        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)))
                    return false;
            }
        }
    } catch (ClassCastException unused) {
        return false;
    } catch (NullPointerException unused) {
        return false;
    }

    return true;
}

考虑以下示例:

Map<String, String> map1 = new HashMap<String, String>();
map1.put("Foo", "Bar");

Map<String, String> map2 = new HashMap<String, String>();
map2.put("Foo", "Bar");

System.out.println(map1.equals(map2)); // true

答案 1 :(得分:0)

首先,你抱怨你的地图有重复的密钥......不可能(除非你使用了严重破坏的实现)。

这应该这样做:

public boolean equals(Object o) {
    if (!(o instanceof MyClass))
        return false;
    MyClass that = (MyClass)o;
    if (map.size() != that.map.size())
        return false;
    for (Map.Entry<String, Object> entry : map) {
        Object a = entry.getValue();
        Object b = that.map.get(entry.getKey());
        if ((a == null ^ b == null) || (a == null && !a.equals(b)))
            return false;
    }
    return true;
}