简体   繁体   English

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

[英]Are there any scenarios where `==` is true but `equals` is false?

In the Standard Java API, are there any scenarios where == will return true , but equals will return false . 在标准Java API中,是否存在==将返回true ,但equals将返回false While theoretically this could be written into a user-defined class rather trivially like this 理论上,这可以写入用户定义的类,而非常像这样

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

Are there any actually baked in examples where for some objects b and c , b == c will return true , but b.equals(c) returns false ? 在实例中是否有任何实际烘焙对于某些对象bcb == c将返回true ,但是b.equals(c)返回false Additionally, would there be any possible benefit to have such a behavior? 此外,有这样的行为会有任何可能的好处吗?

No*. 没有*。

The contract for equals has 5 rules , and the first one covers this case: equals合同有5条规则 ,第一条规则涵盖了这个案例:

The equals method implements an equivalence relation on non-null object references: equals方法在非null对象引用上实现等价关系:

  • It is reflexive: for any non-null reference value x, x.equals(x) should return true. 它是自反的:对于任何非空引用值x,x.equals(x)应该返回true。
  • It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true. 它是对称的:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true。
  • It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true. 它是传递性的:对于任何非空引用值x,y和z,如果x.equals(y)返回true而y.equals(z)返回true,则x.equals(z)应返回true。
  • It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified. 它是一致的:对于任何非空引用值x和y,x.equals(y)的多次调用始终返回true或始终返回false,前提是不修改在对象的equals比较中使用的信息。
  • For any non-null reference value x, x.equals(null) should return false. 对于任何非空引用值x,x.equals(null)应返回false。

Any object in the Java standard library that violates reflexivity would be a bug, and if you do discover such an object in the API, report it to Oracle. Java标准库中违反自反性的任何对象都是错误,如果您确实在API中发现了这样的对象,请将其报告给Oracle。

*Less can be said for third-party libraries. *第三方图书馆可以说较少。 Developers make mistakes or are ignorant of the equals contract. 开发人员犯错误或不了解equals合同。 Generally this also qualifies as a bug in a third-party library, but YMMV. 通常,这也可以作为第三方库中的错误,但是YMMV。

In the Standard Java API, are there any scenarios where == will return true , but equals will return false [?] 在标准Java API中,是否存在==将返回true ,但equals将返回false [?]

Not as far as I am aware, and I am confident that any examples you discovered would be considered bugs. 不是我所知道的,我相信你发现的任何例子都会被视为错误。

In particular, if x and y are references such that x == y , then it must be the case that x.equals(y) evaluates to the same result as x.equals(x) . 特别是,如果xyx == y引用,则必须是x.equals(y)求值与x.equals(x)相同的结果。 The contract for Object.equals() (in its docs) says this, in part: Object.equals()的合同(在其文档中)说明了这一点:

The equals method implements an equivalence relation on non-null object references: equals方法在非null对象引用上实现等价关系:

  • It is reflexive : for any non-null reference value x , x.equals(x) should return true . 它是自反的 :对于任何非空引用值xx.equals(x)应该返回true

Thus any override of Object.equals() is semantically incorrect if it produces, for any references x and y , the result that x == y && !x.equals(y) is true. 因此,如果对于任何引用xy产生x == y && !x.equals(y)为真的结果,则Object.equals()任何重写在语义上都是不正确的。

In the Standard Java API, are there any scenarios where == will return true , but equals will return false . 在标准Java API中,是否存在==将返回true ,但equals将返回false

I'm not sure if this is exactly what you have in mind, but implementations of equals are not required to be threadsafe, and are not required to explicitly check if the argument is the same instance as this . 我不确定这是否与您的想法完全相同,但equals实现不需要线程安全,并且不需要显式检查参数是否与this实例相同。 So it's quite possible, in principle, for foo.equals(foo) to return false if foo is simultaneously being modified in another thread. 因此,原则上foo.equals(foo)很可能在另一个线程中同时修改foo返回false

I doubt any JDK class is explicitly documented as not including this check; 我怀疑任何JDK类都被明确记录为包括此检查; rather, that's considered an implementation detail, except for classes where that is the only check. 相反,这被认为是一个实现细节,除了那是唯一的检查。 But I've managed to get sb.equals(sb) to at least raise an ArrayIndexOutOfBoundsException when sb is a StringBuilder to which another thread is busily adding elements; 但是当sb是另一个线程忙于添加元素的StringBuilder时,我设法让sb.equals(sb)至少引发一个ArrayIndexOutOfBoundsException ; so if you're particularly unlucky in your timing, it should also be capable of returning false . 所以,如果你的时间特别不吉利,它也应该能够返回false

Additionally, would there be any possible benefit to have such a behavior? 此外,有这样的行为会有任何可能的好处吗?

I really don't think so. 我真的不这么认为。 The whole purpose of equals is to support things like Set and Map and Assert.assertEquals and so on. equals的整个目的是支持SetMap以及Assert.assertEquals类的东西。 There are plenty of use-cases that don't use equals at all, but I can't imagine a non-terrible piece of code that does use equals but wants it to not denote a form of equality that's satisfied by identity. 有很多用例根本不使用equals ,但是我无法想象一个非可怕的代码片段确实使用了equals但是希望它不能表示一种由身份满足的平等形式。

That said, it's certainly possible for a non-terrible piece of code to have a bug that accidentally causes this. 也就是说,一个不可怕的代码片段肯定有可能出现一个意外导致此错误的错误。 For example, I mentioned in a comment above that java.util.Date and java.sql.Timestamp have a design mistake (now officially codified) whereby date.equals(ts) can be true but ts.equals(date) is false . 例如,我在上面的评论中提到java.util.Datejava.sql.Timestamp有一个设计错误(现在正式编码),其中date.equals(ts)可以为truets.equals(date)false Someone trying to address this sort of issue might modify java.util.Date to include a check if (that.getClass() == Date.class) ; 试图解决此类问题的人可能会修改java.util.Date以包含检查if (that.getClass() == Date.class) ; but then this would result in a non-reflexive equals implementation in any subclass that didn't explicitly override the parent implementation. 但是这会导致在没有显式覆盖父实现的任何子类中的非自反equals实现。 (Of course, I wouldn't expect such a mistake in the JDK.) (当然,我不希望JDK出现这样的错误。)

Writing equals correctly in the face of inheritance is actually rather tricky, but fortunately there's a known solution that addresses all the intricacies in a simple way: http://www.artima.com/lejava/articles/equality.html . 在面向继承时正确地编写equals实际上相当棘手,但幸运的是,有一种已知的解决方案可以通过简单的方式解决所有复杂问题: http//www.artima.com/lejava/articles/equality.html

As you pointed out, it is certainly possible to implement equals such that x == x but !x.equals(x) . 正如您所指出的,当然可以实现equals x == x但是!x.equals(x) However, doing so would violate the documentated behavior of equals , which states that this property must hold for any valid implementation. 但是,这样做会违反equals记录行为 ,该行为表明此属性必须适用于任何有效的实现。 So you won't find any examples in the Java standard API that do this (unless there's a bug somewhere), and you'll find plenty of code that relies implicitly or explicitly on equals not behaving this way. 所以你不会在Java标准API中找到任何这样做的例子(除非某处有错误),并且你会发现大量的代码隐式或明确地依赖于equals而不是这种方式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM