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:
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
.
下一篇: 重写正确的Java等于方法