java - compare consistent with equals 是什么意思?如果我的类(class)不遵循这个原则,可能会发生什么?

标签 java comparison equals comparator comparable

来自 TreeMap 的 JavaDoc:

Note that the ordering maintained by a sorted map (whether or not an explicit comparator is provided) must be consistent with equals if this sorted map is to correctly implement the Map interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Map interface is defined in terms of the equals operation, but a map performs all key comparisons using its compareTo (or compare) method, so two keys that are deemed equal by this method are, from the standpoint of the sorted map, equal. The behavior of a sorted map is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Map interface.

有人可以举一个具体的例子来说明如果排序与 equals 不一致时可能出现的问题吗?以具有自然顺序的用户定义类为例,即它实现了 Comparable 。 JDK 中的所有内部类是否都维护此不变性?

最佳答案

这是一个简单但实​​际的例子,说明如果比较方法与 equals 不一致会发生什么。在JDK中,BigDecimal实现了Comparable,但其比较方式与equals不一致。例如:

> BigDecimal z = new BigDecimal("0.0")
> BigDecimal zz = new BigDecimal("0.00")
> z.compareTo(zz)
0
> z.equals(zz)
false

这是因为BigDecimal的比较方法只考虑了数值,而equals还考虑了精度。由于 0.00.00 具有不同的精度,因此即使它们具有相同的数值,它们也不相等。 (有关解释,请参阅 this answer .)

下面是一个示例,说明 TreeSet 违反 Set 的一般契约意味着什么。 (这与 TreeMapMap 的情况相同,但使用集合更容易演示。)让我们将 contains 的结果与结果进行比较从集合中取出元素并调用 equals:

> TreeSet<BigDecimal> ts = new TreeSet<>()
> ts.add(z)
> ts.contains(z)
true
> z.equals(ts.iterator().next())
true
> ts.contains(zz)
true
> zz.equals(ts.iterator().next())
false

这里令人惊讶的是 TreeSet 说它包含对象 zz,但它不等于集合中实际包含的元素。原因是 TreeSet 使用它的比较方法 (BigDecimal.compareTo) 来确定集合成员资格,而不是 equals

现在让我们比较一下 TreeSetHashSet:

> HashSet<BigDecimal> hs = new HashSet<>(ts)
> hs.equals(ts)
true
> ts.contains(zz)
true
> hs.contains(zz)
false

这很奇怪。我们有两个相等的集合,但是一个集合说它包含一个对象,而另一个集合说它不包含同一个对象。同样,这反射(reflect)了 TreeSet 使用的是比较方法,而 HashSet 使用的是 equals

现在让我们将另一个对象添加到 HashSet 中,看看会发生什么:

> HashSet<BigDecimal> hs2 = new HashSet<>()
> hs2.add(zz)
> ts.equals(hs2)
true
> hs2.equals(ts)
false

这很奇怪。一组说它等于另一组,但另一组说它不等于第一组!要理解这一点,您需要了解如何确定集合的相等性。如果 a) 它们具有相同的大小,并且 b) 另一个集合中的每个元素也包含在这个集合中,则两个集合被认为是相等的。也就是说,如果你有

set1.equals(set2)

然后相等算法查看大小,然后遍历 set2,并针对每个元素检查该元素是否包含在 set1 中。这就是不对称的来源。当我们这样做时

ts.equals(hs2)

两个集合的大小都是 1,所以我们继续迭代步骤。我们迭代 hs2 并使用然后调用 TreeSet.contains 方法——它使用比较方法。就TreeSet而言,它等于HashSet hs2。

当我们这样做的时候

hs2.equals(ts)

比较是相反的。我们遍历 TreeSet 并获取它的元素,然后询问 hs2 它是否 包含 该元素。由于HashSet.contains使用了equals,所以返回false,整体结果为false。

关于java - compare consistent with equals 是什么意思?如果我的类(class)不遵循这个原则,可能会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12123960/

相关文章:

java - 使用 gradle 的应用程序出现错误 "Native method not found"

java - 触发 Gradle 测试时无法使用 commons-exec 在 Java 中运行命令行

java - “如果”和 'Else' 在 Java 中不起作用?

java - 为什么可以在 Java 中通过引用来比较不兼容的类型?

c++ - 将一个字符与 C++ 中的各种字符类进行比较

dictionary - groovy 中的 bool 方法总是返回 true

java - 如何从 Java 中的 HttpResponse 获取单个表单字段并将其写入文件?

java - 比较字节值?

java - 如何让单元测试在 java 7 : java. lang.VerifyError 中运行:在分支目标处期望堆栈映射框架

c# - GetHashCode问题