Java 比较两张地图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24814577/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Comparing two maps
提问by noMAD
I have two maps declared as Map<String, Object>
. The Object
here could be another Map<String, Object>
(and so on). I want to check if two maps are exactly the same without knowing their depth. Instead of using recursion can I compare the output of the toString()
called on each map? Or is there a simpler way to compare the maps?
我有两张地图声明为Map<String, Object>
. 在Object
这里可以是另一个Map<String, Object>
(依此类推)。我想在不知道深度的情况下检查两张地图是否完全相同。我可以比较toString()
每个地图上调用的输出,而不是使用递归吗?或者有没有更简单的方法来比较地图?
采纳答案by Menios
Quick Answer
快速回答
You should use the equals
method since this is implemented to perform the comparison you want. toString()
itself uses an iterator just like equals
but it is a more inefficient approach. Additionally, as @Teepeemm pointed out, toString
is affected by order of elements (basically iterator return order) hence is not guaranteed to provide the same output for 2 different maps (especially if we compare two different maps).
您应该使用该equals
方法,因为这是为了执行您想要的比较而实现的。toString()
本身就像使用迭代器一样,equals
但它是一种效率更低的方法。此外,正如@Teepeemm 所指出的,toString
受元素顺序(基本上是迭代器返回顺序)的影响,因此不能保证为 2 个不同的地图提供相同的输出(尤其是当我们比较两个不同的地图时)。
Note/Warning: Your question and my answer assume that classes implementing the map interface respect expected toString
and equals
behavior. The default java classes do so, but a custom map class needs to be examined to verify expected behavior.
注意/警告:您的问题和我的回答假定实现地图接口的类尊重预期toString
和equals
行为。默认 java 类这样做,但需要检查自定义地图类以验证预期行为。
See: http://docs.oracle.com/javase/7/docs/api/java/util/Map.html
请参阅:http: //docs.oracle.com/javase/7/docs/api/java/util/Map.html
boolean equals(Object o)
Compares the specified object with this map for equality. Returns true if the given object is also a map and the two maps represent the same mappings. More formally, two maps m1 and m2 represent the same mappings if m1.entrySet().equals(m2.entrySet()). This ensures that the equals method works properly across different implementations of the Map interface.
比较指定对象与此映射是否相等。如果给定对象也是一个映射并且这两个映射表示相同的映射,则返回 true 。更正式地,如果 m1.entrySet().equals(m2.entrySet()),则两个映射 m1 和 m2 表示相同的映射。这确保了 equals 方法可以在 Map 接口的不同实现中正常工作。
Implementation in Java Source (java.util.AbstractMap)
Java Source 中的实现(java.util.AbstractMap)
Additionally, java itself takes care of iterating through all elements and making the comparison so you don't have to. Have a look at the implementation of AbstractMap
which is used by classes such as HashMap
:
此外,java 本身负责遍历所有元素并进行比较,因此您不必这样做。看看它的实现AbstractMap
被类使用,例如HashMap
:
// Comparison and hashing
/**
* Compares the specified object with this map for equality. Returns
* <tt>true</tt> if the given object is also a map and the two maps
* represent the same mappings. More formally, two maps <tt>m1</tt> and
* <tt>m2</tt> represent the same mappings if
* <tt>m1.entrySet().equals(m2.entrySet())</tt>. This ensures that the
* <tt>equals</tt> method works properly across different implementations
* of the <tt>Map</tt> interface.
*
* <p>This implementation first checks if the specified object is this map;
* if so it returns <tt>true</tt>. Then, it checks if the specified
* object is a map whose size is identical to the size of this map; if
* not, it returns <tt>false</tt>. If so, it iterates over this map's
* <tt>entrySet</tt> collection, and checks that the specified map
* contains each mapping that this map contains. If the specified map
* fails to contain such a mapping, <tt>false</tt> is returned. If the
* iteration completes, <tt>true</tt> is returned.
*
* @param o object to be compared for equality with this map
* @return <tt>true</tt> if the specified object is equal to this map
*/
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;
}
Comparing two different types of Maps
比较两种不同类型的地图
toString
fails miserably when comparing a TreeMap
and HashMap
though equals
does compare contents correctly.
toString
比较 a 时失败了TreeMap
,HashMap
虽然equals
确实正确比较了内容。
Code:
代码:
public static void main(String args[]) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("2", "whatever2");
map.put("1", "whatever1");
TreeMap<String, Object> map2 = new TreeMap<String, Object>();
map2.put("2", "whatever2");
map2.put("1", "whatever1");
System.out.println("Are maps equal (using equals):" + map.equals(map2));
System.out.println("Are maps equal (using toString().equals()):"
+ map.toString().equals(map2.toString()));
System.out.println("Map1:"+map.toString());
System.out.println("Map2:"+map2.toString());
}
Output:
输出:
Are maps equal (using equals):true
Are maps equal (using toString().equals()):false
Map1:{2=whatever2, 1=whatever1}
Map2:{1=whatever1, 2=whatever2}
回答by niculare
As long as you override equals()
on each key and value contained in the map, then m1.equals(m2)
should be reliable to check for maps equality.
只要您覆盖equals()
映射中包含的每个键和值,那么m1.equals(m2)
检查映射相等性就应该是可靠的。
The same result can be obtained also by comparing toString()
of each map as you suggested, but using equals()
is a more intuitive approach.
通过toString()
按照您的建议比较每个地图也可以获得相同的结果,但使用equals()
是一种更直观的方法。
May not be your specific situation, but if you store arrays in the map, may be a little tricky, because they must be compared value by value, or using Arrays.equals()
. More details about this see here.
可能不是你的具体情况,但如果你在地图中存储数组,可能有点棘手,因为它们必须逐值比较,或者使用Arrays.equals()
. 有关这方面的更多详细信息,请参阅此处。