Overriding Proper Java equals method

I am overriding the equals() method in a Java class and found a conundrum that I can't explain.

The standard equals() contract states this:

  • It is reflexive: for any reference value x, x.equals(x) should return true.
  • It is symmetric: for any reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any 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.
  • It is consistent: for any 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 object is modified.
  • For any non-null reference value x, x.equals(null) should return false.
  • Therefore, the standard equals() method would be constructed like so:

    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);
    }
    

    Given class Foo and and class Bar extends Foo , both with a member variable String baz , the standard equals() method inside Foo looks like:

    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);
    }
    

    Whereas the standard equals() method inside Bar looks like:

    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);
    }
    

    If I had objects Foo foo = new Foo("Test"); and Bar bar = new Bar("Test"); , and I called foo.equals(bar) , this would return true . If I called bar.equals(foo) , by the symmetric clause of the equals() contract, this is broken because inside equals() of Bar , (!(other instanceof Bar)) is true , making Bar 's equal() method return false , which isn't correct, it should be true , by logic (both objects String baz are equal to each other), and by the symmetry clause, where if x.equals(y) , y.equals(x) is inherently true .

    I'm aware of the getClass() vs instanceof argument for overriding equals() and don't want another one of these arguments.

    This brings me to my actual question. In such a case, how does one properly override the equals() method that follows the standard Java contract for equality?


    According to your question

  • Foo can equal Bar if they have the same baz
  • Foo can equal Foo if they have the same baz
  • Bar can equal Bar if they have the same baz
  • This clearly shows that Foo and Bar will have the exact same implementation of equals() . Therefore, you should not override it at all.

    If you were to try to ignore this and override it anyway, you would reach one obvious conclusion: you can't downcast a Bar to a Foo , but you can cast both arguments to Bar . As soon as you do that, you will realize that you could have simply used .equals() from Bar .

    链接地址: http://www.djcxy.com/p/76222.html

    上一篇: Comparable和(MyClass)null

    下一篇: 重写正确的Java等于方法