覆盖正确的Java等于方法

时间:2014-02-26 21:01:45

标签: java oop override equals

我重写了Java类中的equals()方法,发现了一个我无法解释的难题。

标准equals()合同声明:

  • 它是反身的:对于任何参考值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。

因此,标准equals()方法的构造方式如下:

public boolean equals(Object other) {
    if (null == other) return false;
    if (this == other) return true;
    if (!(other instanceof MyClassName)) return false;
    MyClassName that = (MyClassName) other;
    return this.myMemberVariable.equals(that.name);
}

鉴于课程Foo和课程Bar extends Foo,两者都有成员变量String bazequals()内的标准Foo方法如下所示:

public boolean equals(Object other) {
    if (null == other) return false;
    if (this == other) return true;
    if (!(other instanceof Foo)) return false;
    Foo that = (Foo) other;
    return this.baz.equals(that.name);
}

equals()内的标准Bar方法如下:

public boolean equals(Object other) {
    if (null == other) return false;
    if (this == other) return true;
    if (!(other instanceof Bar)) return false;
    Barthat = (Bar) other;
    return this.baz.equals(that.name);
}

如果我有对象Foo foo = new Foo("Test");Bar bar = new Bar("Test");,并且我调用foo.equals(bar),则会返回true。如果我通过bar.equals(foo)合同的对称条款调用equals(),则会因为equals() Bar(!(other instanceof Bar)) true Bar而被打破,使equal()的{​​{1}}方法返回false,这是不正确的,它应该是true,逻辑(两个对象String baz等于彼此),以及对称性条款,如果x.equals(y)y.equals(x)本身就是true

我知道覆盖getClass()的{​​{1}} vs instanceof参数,并且不想要其中一个参数。

这让我想到了我的实际问题。在这种情况下,如何正确地覆盖遵循标准Java协定的equals()方法以实现相等?

1 个答案:

答案 0 :(得分:1)

根据你的问题

    如果
  • Foo具有相同的Bar
  • ,则baz可以等于Foo 如果
  • Foo具有相同的baz
  • ,则Bar可以等于Bar 如果
  • baz具有相同的Foo
  • ,则Bar可以等于equals()

这清楚地表明BarFoo将{em>与Bar完全相同的实现。因此,您根本不应该覆盖它。

如果你试图忽略这一点并覆盖它,你会得出一个明显的结论:你不能将.equals()转发给Bar,但你可以将两个参数都转换为{{1}}。一旦你这样做,你就会意识到你可以简单地使用{{1}}中的{{1}}。