【发布时间】:2011-05-04 04:52:09
【问题描述】:
在我的类的 equals() 方法中,我使用私有实例 HashMap 变量来比较相等性。但是,在比较它们的 HashMap 变量时,两个不同的对象仍然显示相等。进一步的研究将我带到了链接:Link Here。但是,它只是说 HashMap1.equals(HashMap2) 不起作用的原因是因为“如果不编写自定义代码,显然无法测试 Java 的数组是否相等。”
我不明白这个原因。谁能指导我一个详细的原因?
【问题讨论】:
在我的类的 equals() 方法中,我使用私有实例 HashMap 变量来比较相等性。但是,在比较它们的 HashMap 变量时,两个不同的对象仍然显示相等。进一步的研究将我带到了链接:Link Here。但是,它只是说 HashMap1.equals(HashMap2) 不起作用的原因是因为“如果不编写自定义代码,显然无法测试 Java 的数组是否相等。”
我不明白这个原因。谁能指导我一个详细的原因?
【问题讨论】:
Java 数组类型上的equals 方法等价于==,因为Java 数组“类”不会覆盖Object.equals。
如果您想“按值”比较数组,您需要使用适当的java.util.Arrays.equals(...) 方法,或者自己实现它。
如果您的HashMap 使用数组作为键或值,那么它将调用数组的equals 方法来测试两个映射之间的键和/或值是否相同。这会使HashMap.equals 行为异常(从您的角度来看)。这就是链接文章所说的。但是,如果您使用数组作为键或值类,数组语义仅会影响HashMap 相等性。如果您不这样做,那么 HashMap::equals 应该会按预期工作。
Map 类上的相等性的 javadocs 有点复杂,但它们基本上归结为获取两个条目集,比较它们的大小,然后执行 s1.containsAll(s2)。当然,这很昂贵,但它应该适用于正确实现 Map 接口的所有 Map 类。
请注意,使用数组作为映射的键是一个坏主意,原因如下:
equals 和hashCode 的语义在大多数情况下对于HashMap 是错误的。对于大多数用例,您需要映射按值而不是对象标识来比较键。equals / hashcode 问题的方法,您可以仍然通过修改数组键来破坏映射的不变量。 【讨论】:
原生 Java 数组没有 .equals() 函数。因此,如果您的哈希图的值(或我想的键)是数组,则 HashMap.equals() 将失败。我怀疑它会依靠 Object.equals() 来检查这两个对象是否实际上是同一个对象。
// something like this
class Object {
public boolean equals( Object o) {
return this == o;
}
}
您可以通过在容器上使用一些变体而不是数组 [] 来回避这个问题,因为容器有自己的 .equals(),它在容器的连续元素上调用 equals(),而不是简单地检查它们是否相同的参考。 Collection.equals 实现的代码可能类似于:
public boolean equals(Object o) {
// sets never equal lists and visa versa
if (o instanceof MyCollectionSubclass) {
Iterator myIterator = iterator();
Iterator theirIterator = ((Collection)o).iterator();
while (myIterator.hasNext() && theirIterator.hasNext()) {
Object myObj = myIterator.next();
Object theirObj = theirIterator.next();
if (!myObj.equals(theirObj)) {
return false;
}
}
// at least one will be false or we wouldn't have left the above while loop
return myIterator.hasNext() == theirIterator.hasNext();
}
// not our class
return false;
}
这可能会产生一个真实的值比较,具体取决于您调用 equals() 时集合的内容所做的事情。
【讨论】:
文章是对的。只要可以使用相同的方法比较键对象和值对象,就可以使用 equals() 方法安全地比较 Hashmap。在文章中,map 值是数组,没有按预期实现 equals()。使用 ArrayList 可以解决问题。
【讨论】:
如果不编写自定义代码,就无法测试 Java 的数组是否相等
这只是一种复杂的说法,即 Java 数组不会覆盖 Object.equals()。因此,如果您使用equals()(这是所有集合类的equals 方法所做的)比较它们,您会得到“实例相等”,而不是“值相等”。
这实际上只是 equals 工作方式不同的一个特例,具体取决于它是否被覆盖。
【讨论】: