是否存在`==`为真但`equals`为假的情况?

时间:2017-01-19 18:37:43

标签: java

在标准Java API中,是否存在==将返回true的情况,但equals将返回false。理论上,这可以写入用户定义的类,而非常像这样

class A {
    public boolean equals(Object o) {
        return this != o;
    }
}

在示例中是否实际出现了某些对象bcb == c将返回true,但b.equals(c)返回false }?此外,有这种行为会有任何可能的好处吗?

4 个答案:

答案 0 :(得分:5)

没有*。

The contract for equals has 5 rules,第一个涵盖了这个案例:

  

equals方法在非null对象引用上实现等价关系:

     
      
  • 它是自反的:对于任何非空引用值x,x.equals(x)应该返回true。
  •   
  • 它是对称的:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true。
  •   
  • 它是传递性的:对于任何非空引用值x,y和z,如果x.equals(y)返回true而y.equals(z)返回true,则x.equals(z)应返回true
  •   
  • 它是一致的:对于任何非空引用值x和y,x.equals(y)的多次调用始终返回true或始终返回false,前提是没有修改在对象上的equals比较中使用的信息。
  •   
  • 对于任何非空引用值x,x.equals(null)应返回false。
  •   

Java标准库中违反自反性的任何对象都是错误,如果您确实在API中发现了这样的对象,请将其报告给Oracle。

*第三方图书馆可以说较少。开发人员犯错误或不了解equals合同。通常,这也可以作为第三方库中的错误,但是YMMV。

答案 1 :(得分:1)

  

在标准Java API中,是否存在==将返回true的情况,但equals将返回false [?]

据我所知,并且我相信您发现的任何示例都会被视为错误。

特别是,如果xyx == y的引用,则必须是x.equals(y)评估与x.equals(x)相同结果的情况}。 Object.equals()的合同(在其文档中)部分说明了这一点:

  

equals方法在非null上实现等价关系   对象引用:

     
      
  • reflexive :对于任何非空参考值xx.equals(x)应返回true
  •   

因此,Object.equals()的任何覆盖在语义上都是错误的,如果它为任何引用xy生成x == y && !x.equals(y)为真的结果。

答案 2 :(得分:1)

  

在标准Java API中,是否存在==将返回true的情况,但equals将返回false

我不确定这是否与您的想法完全相同,但equals的实现不需要线程安全,并且不需要显式检查参数是否与this。原则上,foo.equals(foo)如果false同时在另一个帖子中进行修改,则foo可能会返回sb.equals(sb)

我怀疑任何JDK类都被明确记录为 not ,包括此检查;相反,这被认为是一个实现细节,除了那是唯一的检查。但是,当ArrayIndexOutOfBoundsExceptionsb时,我已设法让StringBuilder至少提出false,另一个线程正在忙于添加元素;所以,如果你的时间特别不吉利,那么它也应该能够返回equals

  

此外,有这种行为会有任何可能的好处吗?

我真的不这么认为。 Set的全部目的是支持MapAssert.assertEquals以及equals等内容。有很多用例根本不使用equals,但我无法想象 使用{{1}的一段非常糟糕的代码但是希望它 not 表示一种被身份所满足的平等形式。

也就是说,对于一个不可怕的代码来说,有一个错误可能会导致错误。例如,我在上面的评论中提到,java.util.Datejava.sql.Timestamp存在设计错误(现已正式编纂),其中date.equals(ts)可以是truets.equals(date)false。尝试解决此类问题的人可能会修改java.util.Date以包含支票if (that.getClass() == Date.class);但是这会导致在任何没有明确覆盖父实现的子类中实现非反身equals。 (当然,我不会在JDK中遇到这样的错误。)

面对继承正确地编写equals实际上相当棘手,但幸运的是,有一种已知的解决方案可以用一种简单的方式解决所有复杂问题:http://www.artima.com/lejava/articles/equality.html

答案 3 :(得分:0)

正如您所指出的,当然可以实现equals x == x!x.equals(x)。但是,这样做会违反documentated behavior of equals,它声明此属性必须适用于任何有效的实现。因此,您无法在Java标准API中找到执行此操作的任何示例(除非出现某处的错误),并且您会发现大量代码在equals上隐式或明确地依赖不这样做。