下面是一个简单但现实的示例,说明如果比较方法与 equals 不一致会发生什么情况。在 JDK 中,实现了,但其比较方法与 equals 不一致。例如:BigDecimal
Comparable
> BigDecimal z = new BigDecimal("0.0")
> BigDecimal zz = new BigDecimal("0.00")
> z.compareTo(zz)
0
> z.equals(zz)
false
这是因为比较方法只考虑数值,还考虑精度。由于 和 具有不同的精度,即使它们具有相同的数值,它们也是不相等的。(有关说明,请参阅此答案。BigDecimal
equals
0.0
0.00
下面是 一个示例,说明 a 违反 总合同意味着什么。(这与 和 的情况相同,但使用集合进行演示会容易一些。让我们将 的结果与将元素从集合中取出并调用的结果进行比较:TreeSet
Set
TreeMap
Map
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
现在让我们比较一下:TreeSet
HashSet
> HashSet<BigDecimal> hs = new HashSet<>(ts)
> hs.equals(ts)
true
> ts.contains(zz)
true
> hs.contains(zz)
false
这很奇怪。我们有两个相等的集合,但一个集合说它包含一个对象,而另一个集合说它不包含相同的对象。同样,这反映了使用比较方法而使用 .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。hs2
TreeSet.contains
TreeSet
HashSet
现在,当我们这样做时
hs2.equals(ts)
比较是相反的。我们迭代并获取其元素,并询问它是否是该元素。由于使用相等,因此返回 false,并且总体结果为 false。TreeSet
hs2
contains
HashSet.contains